У меня есть следующий упрощенный скрипт bash
#!/bin/bash
files=("$@")
if [ "X$files" = "X" ]; then
files=$HOME/print/*.pdf;
fi
for file in "${files[@]}"; do
ls "$file";
done
Если я передам аргументы (имена файлов) в качестве параметров, этот скрипт выведет правильные имена файлов. С другой стороны, если я не передам аргументы, он напечатает
/home/user/print/*.pdf: No such file or directory
Почему в этом случае имена файлов не раскрываются и как это исправить? Обратите внимание , что я использую files=("$@")
и "${files[@]}"
конструкции , потому что я читал , что это должно быть более предпочтительным , чем обычные «файлы = $ *».
files=$*
когда - либо обычно ? Это совершенно неправильно .Ответы:
Вы назначаете
files
в качестве скалярной переменной вместо переменной массива .В
Вы назначая некоторую строку , как
/home/highsciguy/print/*.pdf
на$files
скаляр (ака строка) переменной.Использование:
или
вместо. Оболочка раскроет этот шаблон глобинга в список путей к файлам и назначит каждый из них элементам
$files
массива .Расширение шара выполняется во время назначения.
Вам не нужно использовать нестандартные функции sh, и вы могли бы использовать свою систему
sh
вместо этогоbash
, написав это:set
назначить"$@"
массив позиционных параметров.Другой подход мог бы заключаться в том, чтобы хранить шаблон смещения в скалярной переменной:
И пусть оболочка расширяет глобус во время раскрытия
$files
переменной.Здесь, поскольку
$files
он не заключен в кавычки (что обычно не следует делать), его расширение подвержено разбиению по словам (которое мы здесь отключили) и генерации глобализации / имени файла.Таким образом,
*.pdf
будет расширен список подходящих файлов. Однако, если они$HOME
содержат подстановочные знаки, их тоже можно развернуть, поэтому все же предпочтительнее использовать переменную массива.источник
Возможно, вы видели такие вещи, как
files=$*
иfiles=~/print/*.pdf
в старых оболочках без массивов, а затемls $files
.Подстановка переменной, которая не находится в двойных кавычках, интерпретирует значение переменной как список разделенных пробелами шаблонов подстановочных знаков оболочки, которые заменяются соответствующими именами файлов, если они есть. Например, после того
files=~/print/*.pdf
,ls $files
расширяется к чему - то , какls
с аргументами/home/highsciguy/print/bar.pdf
,/home/highsciguy/print/foo.pdf
и т.д. В случаеfiles=$*
, это назначение объединяющее аргументы , передаваемые в сценарий с пробелами между ними, иls $files
расколов их обратно.Все это ломается, если у вас есть имена файлов, содержащие пробельные символы или символы Globbing, поэтому вы не должны так поступать. Вместо этого используйте массивы.
Обратите внимание, что
var=(…)
."$files"
пусто, когдаfiles
является массивом, элемент индекса 0 которого не установлен, или пустой строкой. Также[ "X$foo" = "X" ]
есть устаревший способ проверить,$foo
является ли пустым: все современные оболочки работают[ -n "$foo" ]
правильно. В Bash вы можете использовать[[ -n $foo ]]
.В оболочках, которые не поддерживают массивы, фактически существует один массив: позиционные параметры оболочки или текущей функции. Здесь вам не нужен
files
массив, на самом деле было бы проще использовать позиционные параметры.источник