Есть ли простой способ установить nullglob для одного шара - PullRequest
20 голосов
/ 03 февраля 2012

В bash, если вы сделаете это:

mkdir /tmp/empty
array=(/tmp/empty/*)

вы обнаружите, что array теперь имеет один элемент, "/tmp/empty/*", а не ноль, как вы хотели бы. К счастью, этого можно избежать, включив опцию оболочки nullglob с помощью shopt -s nullglob

Но nullglob является глобальным, и при редактировании существующего сценария оболочки может что-то сломать (например, кто-то проверял код выхода 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, есть ли?

Ответы [ 5 ]

16 голосов
/ 03 февраля 2012

Сбросьте его, когда закончите:

shopt -u nullglob

И правильно (т.е. сохраните предыдущее состояние):

shopt -u | grep -q nullglob && changed=true && shopt -s nullglob
... do whatever you want ...
[ $changed ] && shopt -u nullglob; unset changed
9 голосов
/ 14 декабря 2013

С помощью 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)

Но к этому моменту может быть проще последовать совету одного из других ответов.

6 голосов
/ 23 января 2016

Это немного лучше, чем ваше первоначальное предложение:

local nullglob=$(shopt -p nullglob) ; shopt -s nullglob

... делайте что хотите ...

$nullglob ; unset nullglob
2 голосов
/ 03 февраля 2012

Это может быть близко к тому, что вы хотите; как это требует выполнения команды для расширения глобуса.

$ ls
file1 file2
$ array=( $(shopt -s nullglob; ls foo*) )
$ ls foo*
ls: foo*: No such file or directory
$ echo ${array[*]}
file1 file2

Вместо установки array в подоболочке мы создаем подоболочку, используя $(), вывод которой захватывается array.

1 голос
/ 27 октября 2016

Это самое простое решение, которое я нашел:

Например, чтобы развернуть литерал **/*.mp3 в глобус только для определенной переменной, вы можете использовать

VAR=**/*.mp3(N)

Источник: https://unix.stackexchange.com/a/204944/56160

...