Подтвердить что ты не робот

Есть ли простой способ установить 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, есть?

4b9b3361

Ответ 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