Посмотрите на эту технику с bash 4.4:
function myf {
if ! [ -t 0 ];then
declare -a args=\($(</dev/stdin)\);
set -- "${args[@]}";
fi;
for i in "$@";do
echo "$i";
echo -----;
done
}
Тестирование:
$ function myf { if ! [ -t 0 ];then declare -a args=\($(</dev/stdin)\);set -- "${args[@]}"; fi;for i in "$@";do echo "$i";echo -----;done }
$ myf 1 "2 3" 4
1
-----
2 3
-----
4
-----
$ echo $'1 "2 3" 4'|myf
1
-----
2 3
-----
4
-----
Тот же результат можно получить и с:
$ echo 1 \"2 3\" 4 |myf
$ echo 1 "'2 3'" 4 |myf
Но echo 1 "2 3" 4
не будет работать, потому что bash игнорирует двойные кавычки в этом синтаксисе:
$ echo 1 "2 3" 4
1 2 3 4
Короче говоря, вы создаете массив files
и расширяете его.
Вы читаете это так:
VAR = ...
означает, что вы назначаете переменную. VAR = (...)
означает, что вы назначаете массив bash переменной.
$ (...)
означает, что вы запускаете команду и получаете ее вывод, в вашем случае список файлов, которые соответствуют заданному шаблону, которые настолько стары, а затем назначают каждый файл элементу в bash множество.
$ {...}
означает, что вы читаете значение переменной, например:
$ SOMEVAR="a value"
$ echo "${SOMEVAR}"
a value
В bash $ VAR
и $ {VAR}
эквивалентны, но нотация $ {VAR}
позволяет вам делать некоторые дополнительные вещи. В частности, echo "$ {VAR} iable"
расширит переменную $ VAR
и объединит ее со строкой iable
, тогда как echo $ VARiable
] попытается расширить переменную $ VARiable
. Вы также можете выполнить некоторую расширенную замену , используя нотацию $ {...}
.
В нашем случае мы читаем файловую переменную с помощью $ {file ...}
. Затем [...]
указывает, что мы читаем массив bash . Итак, мы пытаемся получить доступ к элементу массива файлов, бит внутри [...]
сообщает нам, какие элементы, это может быть 1
для доступа к первому элементу, 2
для доступа ко второму и так далее (массивы bash индексируются с 1, а не с 0). @
означает все элементы, поэтому мы пытаемся получить доступ ко всем элементам массива bash под названием file
.
Вы можете попробовать это со следующим:
% ARRAY=("a value" "another value" "fred")
% for x in "${ARRAY[@]}"; do echo "$x"; done
a value
another value
fred
Преимущество использования массивов вместо строк, разделенных пробелами, заключается в том, что вы можете включать пробелы в значения, как указано выше. Таким образом, в вашем случае каждый файл в массиве files
будет рассматриваться как отдельный аргумент, а пробелы в именах файлов будут обрабатываться правильно.
По сути, ваш snipit находит и собирает список файлов и передает их как отдельные аргументы команде tar.
files = (...)
создает массив имен файлов
Синтаксис "$ {files [@]}"
означает _каждый элемент массива; т.е. каждое найденное имя файла. Обратите внимание на окружение "..."
, это важно для предотвращения разделения некоторых имен файлов.
(Это может привести к сбою, если в любом имени файла есть возврат каретки).
files = (...)
создает массив строк в ksh
, который создал этот синтаксис, и в оболочках, которые позже приняли его, например bash
и другие.
$ (find / var / cdrs -maxdepth 1 -name \ *. C * R -mtime +150)
создает список путей, разделенных пробелами, соответствующих указанным условиям. Однако, если имя файла содержит один из символов IFS, обычно пробел, табуляцию и перевод строки, имя файла будет разделено на части, а затем будет неправильно сохранено в массиве.
"$ {files [@]}"
расширяется до списка строк, в которых каждый элемент заключен в кавычки. Цитирование элементов здесь бесполезно, поскольку массив в любом случае не может содержать пробелов, табуляции или возврата каретки, как указано в предыдущем абзаце. Затем этот синтаксис можно немного упростить с помощью $ {files [*]}
.