#bash #shell #variables #scripting
#bash #оболочка #переменные #сценарии
Вопрос:
Я довольно новичок в написании сценариев bash. Кажется, я не могу получить правильное значение моих переменных подсчета для отображения в конце while
цикла в моем скрипте bash.
Справочная информация: У меня есть довольно простая задача: я хотел бы передать текстовый файл, содержащий список путей к файлам, скрипту bash, заставить его проверить существование этих файлов и подсчитать количество существующих / отсутствующих файлов. Я заставил большую часть скрипта работать, за исключением части подсчета.
N=0
correct=0
incorrect=0
cat $1 | while read filename ; do
N=$((N 1))
echo "$N"
if ! [ -f $filename ]; then
incorrect=$((incorrect 1))
else
correct=$((correct 1))
fi
done
echo "# of Correct Paths: $correct"
echo "# of Incorrect Paths: $incorrect"
echo "Total # of Files: $N"
Если у меня есть список из 5 файлов, 4 из которых существуют, я ожидаю получить следующий вывод (обратите внимание на echo
команду в while
цикле):
1
2
3
4
5
# of Correct Paths: 4
# of Incorrect Paths: 1
Total # of Files: 5
Вместо этого я получаю:
1
2
3
4
5
# of Correct Paths: 0
# of Incorrect Paths: 0
Total # of Files: 0
Что случилось со значениями этих переменных? У Google было много предложений сомнительного качества, и я думаю, что мог бы заставить это работать с помощью немного большего поиска, но краткое объяснение того, что я делаю неправильно, было бы очень полезно.
Комментарии:
1. Вы можете использовать
((N ))
и((incorrect ))
(или даже((N =1))
) для более сжатого синтаксиса.
Ответ №1:
Это потому, что вы используете бесполезную cat
команду с каналом, вызывая создание подоболочки. Попробуйте это без cat
:
while read filename ; do
N=$((N 1))
....
done < file
Комментарии:
1. Спасибо, это решило мою проблему. Это лучший способ передать файл в цикл while? (т. Е. готово < файл). Это работает, но мне кажется немного неловким.
2. @spadina. ну,
<
,<<
>
и>>
являются базовыми операторами в bash. Вы увидите это много раз при написании сценариев bash. Привыкание к этому облегчит вам эту «неловкость».3. Если вам нужно сохранить подоболочку для вашего цикла, вы также можете записать обновленную переменную во временный файл. Например:
N=`cat /tmp/n`; ((N )); echo $N > /tmp/n
. Когда цикл будет завершен, снова прочитайте его из файла:N=`cat /tmp/n`
.
Ответ №2:
В качестве альтернативы, если вы по какой-то причине хотите сохранить cat
, вы можете исправить свой скрипт, просто добавив эту строку перед cat
инструкцией:
shopt -s lastpipe
Ответ №3:
В более общем плане, иногда вы хотите передать вывод команды по каналу. Вот пример, в котором используется подстановка процесса для удаления файлов JavaScript, которые Git собирается зафиксировать, и подсчитывается количество файлов, которые завершились ошибкой:
# $@ glob
git-staged-files() {
git diff --cached -C -C -z --name-only --relative --diff-filter=ACMRTUXB "$@"
}
# $@ name
map() { IFS= read -rd $'' "$@"; }
declare -i errs=0
while map file; do
echo "Checking $file..."
git show ":$file"|
eslint --stdin --stdin-filename "$file" || (( errs))
done < <(git-staged-files *.js)
((errs)) amp;amp; echo -en "e[31m$errs files with errors.e[00m " >amp;2 || :