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

Как назначить выражение glob переменной в Bash script?

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

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

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

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

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

Я читал справочное руководство bash (v 3.2) и не вижу никакой причины для того, чтобы globing filename не состоялся (я не передаю -f в оболочку) или что-либо, что я может быть настроен для обеспечения того, чтобы выполнялось глобирование.

4b9b3361

Ответ 1

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

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

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

eval ls $dirs

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

dirs=/content/{dev01,dev02}*

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

Ответ 2

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

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

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

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

Ответ 3

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

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

Ответ 4

Я подозреваю, что вам нужен массив, но это ограничит вас новыми слоями. Это заставка, чем использование 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}"

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

Ответ 5

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

Что вам нужно, расширенное подталкивание:

shopt -s extglob # likely already set in interactive shells

dirs=/content/@(dev01|dev02)
ls $dirs

Ответ 6

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

list_of_results=(pattern)

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

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

Ответ 7

ls `echo $dirs` 

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