Как назначить выражение glob переменной в скрипте Bash? - PullRequest
42 голосов
/ 15 декабря 2008

Когда следующие две строки кода выполняются в скрипте bash, «ls» жалуется, что файлы не существуют:

dirs=/content/{dev01,dev02}
ls -l $dirs

Когда я запускаю скрипт с параметром -x, он, кажется, передает переменную в одинарных кавычках (что предотвратит глобализацию):

+ dirs=/content/{dev01,dev01}
+ ls -l '/content/{dev01,dev01}'
ls: /content/{dev01,dev01}: No such file or directory

Если я выполняю команду "ls" из моей интерактивной оболочки (без кавычек), она возвращает две директории.

Я читал Справочное руководство по Bash (v 3.2) и не вижу никакой причины, по которой не происходит глобализация имени файла (я не передаю -f в оболочку), или что-либо, что я могу установить чтобы гарантировать, что случится сглаживание.

Ответы [ 8 ]

30 голосов
/ 15 декабря 2008

Я думаю, что это порядок расширений:

Порядок расширений: brace expansion, расширение тильды, параметр, variable и арифметическое расширение и подстановка команды (сделано в мода слева направо), слово расщепление и pathname expansion.

Так что, если ваша переменная подставляется, расширение скобок больше не происходит. Это работает для меня:

eval ls $dirs

Будьте очень осторожны с Eval. Это выполнит материал дословно. Так что, если dirs содержит f{m,k}t*; some_command, some_command будет выполнен после завершения ls. Он выполнит строку, которую вы дадите eval в текущей оболочке. /content/dev01 /content/dev02 будет передано ls, независимо от того, существуют они или нет. Помещение * после того, как материал делает это расширением пути, и он пропустит несуществующие пути:

dirs=/content/{dev01,dev02}*

Я не уверен на 100% в этом, но для меня это имеет смысл.

22 голосов
/ 15 декабря 2008

Здесь - отличное обсуждение того, что вы пытаетесь сделать.

Краткий ответ: вам нужен массив:

dirs=(/content/{dev01,dev01})

Но то, что вы делаете с результатами, может оказаться более сложным, чем то, к чему вы стремились, я думаю.

8 голосов
/ 15 декабря 2008

Это не имя файла, это расширение скобки. Разница невелика, но она существует - при глобализации имени файла вы получите только существующие файлы, в то время как при расширении фигурных скобок вы можете генерировать любые типы строк.

http://www.gnu.org/software/bash/manual/bashref.html#Brace-Expansion

http://www.gnu.org/software/bash/manual/bashref.html#Filename-Expansion

Вот что у меня сработало:

#!/bin/sh
dirs=`echo ./{dev01,dev02}`
ls $dirs
6 голосов
/ 24 мая 2016

Для людей (таких как я), которые находят это через Google, ответы @Peter и @ feoh являются общим решением «Как получить переменные в скрипте bash».

list_of_results=(pattern)

сохранит существующие имена файлов, соответствующие pattern, в массив list_of_results. Каждый элемент list_of_results будет содержать одно имя файла, пробелы и все.

Вы можете получить доступ к каждому результату как "${list_of_results[<index>]}" для <index>, начиная с 0. Вы можете получить весь список, правильно заключенный в кавычки, как "${list_of_results[@]}".

2 голосов
/ 08 марта 2016

Я подозреваю, что вам нужен массив, но это ограничит вас новыми битами. Это безопаснее, чем при использовании eval.

dirs=( /"content with spaces"/{dev01,dev02} )

dirs=( /content/{dev01,dev02} )
ls -l "${dirs[@]}"

/content/{dev01,dev02}

расширится до:

"/content/dev01" "/content/dev02"

Существование этих каталогов не имеет отношения к расширению.

Это становится непредсказуемым, когда вы присваиваете переменную для фигурной скобки.

dirs=/content/{dev01,dev02}

может превратиться в

"/content/dev01"

или

"/content/dev01 /content/dev02"

или

"/content/dev01" "/content/dev02"

или

"/content/{dev01,dev02}"

Если вы заключите в скобки каким-либо образом, они не будут расширяться, поэтому результат будет содержать скобки и будет в основном бессмысленным.

1 голос
/ 08 марта 2016

Поскольку вы хотите обрабатывать файлы , не следует использовать скобки. Использование расширения скобки в этом случае является антипаттерном и определенно не подходит для работы.

То, что вы хотите, это расширенная глобализация :

shopt -s extglob # likely already set in interactive shells

dirs=/content/@(dev01|dev02)
ls $dirs
0 голосов
/ 07 ноября 2018

Проблема, которую никто не решал, заключается в том, что переменная имеет значение.

dirs=/content/{dev01,dev02}

расширяется не так, как

echo /content/{dev01,dev02}

Вопрос в том, как присвоить результаты расширения для dirs

См .: Как использовать подстановку Bash в объявлении переменной

0 голосов
/ 15 декабря 2008
ls `echo $dirs` 

работает под Cygwin.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...