Итерация по значениям $@
Я хотел бы перебрать аргументы, данные скрипту bash, например:
./bash_script file1 file2 file3
$@
дает мне все файлы, предоставленные сценарию, но как мне перебрать файлы?
я бы хотел cat
каждый файл и удалить содержимое с помощью awk
(Я знаю, как это сделать, это распаковка $@
это меня смутило)
2 ответа
Хитрость заключается в двойной кавычке, как в "$@"
,
foo(){
printf ' ->%s\n' "$@";
}
foo "a b" c "d e"
эквивалентно:
printf ' ->%s\n' "a b" c "d e"
Если $@
в вышесказанном не стоит двойных кавычек, тогда вы получите:
printf ' ->%s\n' a b c d e
из-за разделения слов на $IFS
персонажи ($IFS
по умолчанию ' '$'\t'$'\n'
пробел, табуляция и перевод строки)
$@ против $*
Двойные кавычки работают следующим образом для любого @-расширения в любом массиве:
$ foo=( "a b" c "d e" )
$ printf ' ->%s\n' "${foo[@]}"
->a b
->c
->d e
В отличие от * расширения (например, $*
, ${foo[*]}
) будет использовать первый символ $IFS
объединить элементы массива в одну строку:
$ foo=( "a b" c "d e" )
$ ( IFS=:; printf ' ->%s\n' "${foo[*]}" )
->a b:c:d e
который, если оставить его без кавычек, снова разделится на этот самый символ IFS:
$ foo=( "a b" c "d e:f:g" )
$ ( IFS=:; printf ' ->%s\n' ${foo[*]} )
->a b
->c
->d e
->f
->g
Трюк для итерации по $@ в циклах for:
"$@"
массив особенный. Если вы хотите перебрать "$@"
в цикле, то вы можете сократить
for variable_name in "$@"; do
...
done
как
for variable_name; do
done
как пропустить in something
часть for
цикл подразумевает in "$@"
,
Это работает даже в оболочках только для POSIX (dash, bourne shell), которые не имеют переменных массива, но поддерживают "$@"
а также "$*
,
Чтобы перебрать их, вы используете двойные кавычки $@
вдоль линий:
for arg in "$@" ; do
echo "--> ${arg}"
done
for arg in "$@"
также может быть написано как for arg
(или даже for arg in
) так как bash
Страница руководства гласит:
for name [ [ in [ word ... ] ] ; ] do list ; done
бла бла бла
Если слово in опущено, команда for выполняет список один раз для каждого установленного позиционного параметра.
Однако я предпочитаю явный вариант.
Следующая стенограмма показывает это в действии:
pax: testprog.sh 1 2 3 '4 5' '' '6 7 8' "9"
--> 1
--> 2
--> 3
--> 4 5
-->
--> 6 7 8
--> 9
И, как в сторону, ваш комментарий об использовании cat
а также awk
изменение файлов может обрушить гнев "бесполезного использования cat
Награда "Толпа":-)
Если вы думаете о чем-то вроде:
cat "${fspec}" | awk 'do something'
затем cat
совершенно ненужно. Вместо этого вы можете использовать:
awk 'do something' "${fspec}"
Я обычно не беспокоюсь о (небольшой) неэффективности запуска дополнительного процесса, но некоторые люди делают.