Есть ли простой способ установить nullglob для одного glob
В bash, если вы это сделаете:
mkdir /tmp/empty
array=(/tmp/empty/*)
вы обнаружите, что array
теперь имеет один элемент, "/tmp/empty/*"
, а не нуль, как вам хотелось бы. К счастью, этого можно избежать, включив опцию оболочки nullglob, используя shopt -s nullglob
Но значение nullglob является глобальным, а при редактировании существующей оболочки script может быть нарушено (например, кто-то проверял код выхода ls foo*
, чтобы проверить, есть ли файлы, начинающиеся с "foo"?). Поэтому, в идеале, я хотел бы включить его только для небольшого объема - в идеале - расширения одного файла. Вы можете отключить его снова, используя shopt -u nullglob
Но, конечно, только если он был отключен раньше:
old_nullglob=$(shopt -p | grep 'nullglob$')
shopt -s nullglob
array=(/tmp/empty/*)
eval "$old_nullglob"
unset -v old_nullglob
заставляет меня думать, что должен быть лучший способ. Очевидное "положить его в подоболочку" не работает, так как, конечно, назначение переменной умирает с подоболочкой. За исключением ожидания группы Austin для импорта синтаксиса ksh93, есть?
Ответы
Ответ 1
С mapfile
в Bash 4 вы можете загрузить массив из подоболочки с чем-то вроде: mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done)
. Полный пример:
$ shopt nullglob
nullglob off
$ find
.
./bar baz
./qux quux
$ mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done)
$ shopt nullglob
nullglob off
$ echo ${#array[@]}
2
$ echo ${array[0]}
bar baz
$ echo ${array[1]}
qux quux
$ rm *
$ mapfile array < <(shopt -s nullglob; for f in ./*; do echo "$f"; done)
$ echo ${#array[@]}
0
- Обязательно закройте
./*
вместо голой *
при использовании echo
для печати имени файла
- Не работает с символами новой строки в имени файла:( как указано derobert
Если вам нужно обрабатывать символы новой строки в имени файла, вам нужно будет сделать гораздо более подробный:
array=()
while read -r -d $'\0'; do
array+=("$REPLY")
done < <(shopt -s nullglob; for f in ./*; do printf "$f\0"; done)
Но к этому моменту может быть проще следовать совету одного из других ответов.
Ответ 2
Отсоедините его, когда закончите:
shopt -u nullglob
И правильно (т.е. сохранить предыдущее состояние):
shopt -u | grep -q nullglob && changed=true && shopt -s nullglob
... do whatever you want ...
[ $changed ] && shopt -u nullglob; unset changed
Ответ 3
Это немного лучше, чем ваше первоначальное предложение:
local nullglob=$(shopt -p nullglob) ; shopt -s nullglob
... делай что хочешь...
$nullglob ; unset nullglob
Ответ 4
Это может быть близко к тому, что вы хотите; как есть, требуется выполнение команды для расширения glob.
$ ls
file1 file2
$ array=( $(shopt -s nullglob; ls foo*) )
$ ls foo*
ls: foo*: No such file or directory
$ echo ${array[*]}
file1 file2
Вместо установки array
в подоболочке, мы создаем подоболочку с помощью $()
, выход которой захватывается array
.
Ответ 5
Это самое простое решение, которое я нашел:
Например, чтобы развернуть литерал **/*.mp3
в глобус только для определенной переменной, вы можете использовать
VAR=**/*.mp3(N)
Источник: https://unix.stackexchange.com/a/204944/56160