Комментарии 35
Прочтите для начала Bash Pitfalls, а то я не знаю с чего начать комментирование Вашей статьи…
for file in $folder/*
Согласен. Не стоит учиться на таких переводах.С пробелами в данном случае прокатит. А вот например если имя файла содержит *, то попробует раскрыть как вайлдкард.
С пробелами в данном случае прокатит
$ ls
folder 1 folder 2
$ for folder in $(ls); do for file in $folder/*; do echo $file; done; done
folder/*
1/*
folder/*
2/*
Если вывод ls
парсить, то не прокатит. А если напрямую раскрывать for file in folder/*
, то вполне:
$ ls -1
a b
c d
$ for i in ./*; do echo $i; done
./a b
./c d
Запутался, про пробелы в каком месте речь :) Да, если в $folder
пробел, тоже сломается.
find /path -print0 |\
while IFS= read -r -d $'\0' path; do
#спасает от... от чего только не спасает, проверить можно просто:
echo -e "${path}"
done
While там для того, чтобы можно было с переменной path оперировать дальше.
С read -d $'\0'
трюк не знал, спасибо :)
Тут кстати ещё одна проблема возникает — while в таков варианте запустит сабшел, изменения переменных в котором не видны в родительском. Поэтому обмен данными с командами, которые внутри while работают, может быть проблематичен.
while в таков варианте запустит сабшел
Это скорее сила привычки и того что «внутренности» while в моём конкретном случае не были нужны. «Исправляется» очень просто:
while IFS= read -r -d $'\0' path; do
echo -e "${path}"
done < <(find /path -print0)
Зачем писать мутные 3 строчки, если можно в одну?
Если одной команды после xargs не достаточно, а нужна сложная обработка, с условиями и переменными.
Пример: https://selivan.github.io/2017/04/08/ansible-check-on-commit-vault-files-are-encrypted.html Вот только закончил писать статью в блог и сразу повод попиарить её на хабре :)
#!/usr/bin/env bash
TOPVAR="this is topvar"
find ~ -maxdepth 1 -type d -print0 |\
while IFS= read -r -d $'\0' path; do
TOPVAR="this is done in subshell"
done
echo -e "subshell version"
#prints - "this is topvar", because pipe creates subshell
echo -e "${TOPVAR}"
#----------------
echo -e ""
# let's do it again without subshell
while IFS= read -r -d $'\0' path; do
TOPVAR="this is not done in the subshell, result is visible"
done < <(find ~ -maxdepth 1 -type d -print0)
echo -e "non-subshell version"
# prints - this is not done in the subshell, result is visible
echo -e "${TOPVAR}"
selivanov_pavel
Не вводите пож. людей в заблуждение фразой
while loop creates separate subshell
Сабшел создаёт пайпа.
Предлагаю также примеры брать более жизненные. Например, тот же анализ passwd — но чтобы результат был осмысленным. Зачем может пригодиться такой вот дамп форматированного файла?
Сколько можно снова и снова плодить по кусочкам разбитые (и не полные) гайды по написанию скриптов на баше?
Есть замечательный документ — http://tldp.org/LDP/abs/html/, кто владеет английским — просто читайте его.
Авторам из ruvds предлагаю помогать перевести вышеупомянутый источник на русский, раз уж так руки чешутся. Пользы будет в разы больше.
Но можете хотя бы оформлять код так, чтобы оно соответствовало bash style, отделять вложенные блоки отступом, именовать переменные в UPPERCASE?
#!/bin/bash
for VAR1 in 1 2 3 4 5 6 7 8 9 10
do
if [ $VAR1 -eq 5 ]
then
break
fi
echo "Number: $VAR1"
done
Нас интересует bash, поэтому первая строка файла будет такой:
#!/bin/bash
Причём на хабре это уже как минимум один раз обсуждалось вот тут (советую пойти по ссылкам вглубь): https://habrahabr.ru/post/319670/#comment_10017494
Если лень искать и ходить по ссылкам, вот хорошо написано:
http://stackoverflow.com/questions/10376206/what-is-the-preferred-bash-shebang
И можно на самом деле продолжать дальше, но мы лишь будем обсуждать то, что уже наверняка обсуждалось и наверняка не один раз.
Не надо парсить /etc/passwd
, надо использовать getent
. Иначе потом эти скрипты не будут работать на хостах, где пользователи прилетают из какого-нибудь LDAP
Всё, что вы напишите в sh, может быть использовано против вас.
Больше рассказывайте "почему" вы делаете так, а не иначе. Даже простое объяснение разницы между
if [ условие ]; then
#
fi
и
if [[ условие ]]
then
#
fi
было бы полезнее, чем десяток очевидных примеров из статьи. Может она и для новичков, но учите новичков не только плохому, пожалуйста.
Чем менять переменную IFS, которая повлияет и на последующую работу (т.е. надо не забыть восстановить), и на вложенные вызовы (как изолировать?), — лучше использовать транслятор символов.
echo $PATH
/mingw64/bin:/usr/local/bin:/usr/bin:/bin:/mingw64/bin:/usr/bin:.......
echo $PATH | tr ':' '\n'
/mingw64/bin
/usr/local/bin
/usr/bin
/bin
/mingw64/bin
/usr/bin
.....
for d in `echo $PATH | tr : '\n'`; do echo "--- $d ---"; done
--- /mingw64/bin ---
--- /usr/local/bin ---
--- /usr/bin ---
--- /bin ---
--- /mingw64/bin ---
--- /usr/bin ---
.....
потом попинговать их по одному, если комп включен то его имя записываем в один файл
если комп выключен, то его имя записываем в другой файл
в cmd bat я это сделал легко
но в линуксе под Win10 со всеми последними обновлениями это сделать не получается
пишет что то про DO и все. пробовал все примеры из этой и других статей
ошибка может отличаться но не работает
ошибка при чтении списка файлов.
#!/bin/bash
for iplist1 in bank_router_ip.txt
do
echo "$iplist1"
done
lin@W10:/mnt/c/Users/IEU$ sh test
: not foundst:
: not foundst:
: not foundst:
: not foundest:
: not foundest:
: not foundest:
test: 36: test: Syntax error: end of file unexpected (expecting «done»)
#!/bin/bash
cat bank_router_ip.txt | while read p; do
echo $p
done
lin@W10:/mnt/c/Users/IEU$ sh test
: not foundst:
: not foundst:
: not foundst:
: not foundest:
: not foundest:
test: 14: test: Syntax error: «done» unexpected (expecting «do»)
#!/bin/bash
for planet in Меркурий Венера Земля Марс Юпитер Сатурн Уран Нептун Плутон
do
echo $planet
done
lin@W10:/mnt/c/Users/IEU$ sh test
: not foundst:
test: 4: test: Syntax error: word unexpected (expecting «do»)
что я не так делаю?
2. test — встроенная команда, не называйте так скрипты
bash-4.4$ cat planets.bash
#!/bin/bash
for planet in Меркурий Венера Земля Марс Юпитер Сатурн Уран Нептун Плутон
do
echo $planet
done
bash-4.4$ bash planets.bash
Меркурий
Венера
Земля
Марс
Юпитер
Сатурн
Уран
Нептун
Плутон
ttest: line 2: $'\r': command not found
ttest: line 4: syntax error near unexpected token `$'do\r''
'test: line 4: `do
Bash-скрипты, часть 2: циклы