РЕДАКТИРОВАТЬ: см. Решение Гордона Дэвиссона для более общего ответа (например, если ваши имена файлов содержат специальные символы). Этот ответ - просто исправление синтаксиса.
Это не будет работать правильно, если имена каталогов содержат пробелы.
chepner
1
Чтобы решить проблему пробелов или специальных символов, сначала объявите массив без каких-либо значений, затем используйте встроенную ARR+=('$(ls -d */)')функцию для редактирования элементов в массиве, используя одинарные кавычки для работы со специальными символами, чтобы добавить или удалить элементы в него. массив. Одиночные кавычки сохраняют буквальные символы и устраняют необходимость в экранировании, чтобы иметь дело с ними в именах каталогов.
Yokai
@Yokai Ваше предложение звучит замечательно, но у меня не сработало на Ubuntu 16.04 или MacOs. Bash расширяет код между одинарными кавычками следующим образом: declare -a ARR; ARR+=('$(ls -d "$INPUT_DIR"/*)')возвращает только$(ls -d $INPUT_DIR/*)
Agile Bean
1
Моя ошибка. Это должны были быть двойные кавычки, чтобы можно было расширить подстановку команд. ARR+=("$(ls -d */)")должно сработать. Если не просто дайте мне знать.
Yokai
2
@Yokai, который добавляет только один элемент (с кучей новых строк в нем), а не один элемент для каждого каталога.
Чарльз Даффи
80
По возможности следует избегать синтаксического анализа вывода ls(см . Вики Грега по этой теме ). Обычно вывод lsбудет неоднозначным, если в любом из имен файлов есть забавные символы. Также обычно это пустая трата времени. В этом случае, когда вы выполняете ls -d */, происходит то, что оболочка расширяется */до списка подкаталогов (который уже является именно тем, что вам нужно), передает этот список в качестве аргументов в ls -d, который просматривает каждый из них и говорит: «Да, это каталог. хорошо »и распечатывает его (в противоречивом, а иногда и неоднозначном формате). Команда lsне делает ничего полезного!
Хорошо, хорошо, он делает одну полезную вещь: если нет подкаталогов, */он останется как есть, lsбудет искать подкаталог с именем «*», но не находить его, печатать сообщение об ошибке, что он не существует (чтобы stderr), а не выводить «* /» (на стандартный вывод).
Более простой способ создать массив имен подкаталогов - использовать glob ( */), не передавая его в ls. Но чтобы избежать добавления "* /" в массив, если фактических подкаталогов нет, вы должны сначала установить nullglob (опять же, см . Вики Грега ):
shopt -s nullglob
array=(*/)
shopt -u nullglob # Turn off nullglob to make sure it doesn't interfere with anything laterecho"${array[@]}"# Note double-quotes to avoid extra parsing of funny characters in filenames
Если вы хотите распечатать сообщение об ошибке при отсутствии подкаталогов, вам лучше сделать это самостоятельно:
if (( ${#array[@]} == 0 )); thenecho"No subdirectories found" >&2
fi
Спасибо за ваш комментарий, хотя он и не отмечен как ответ, он был достаточно информативным, и я ценю его.
Jake H
Что делать, если вы не хотите /использовать имя каталога?
shinzou
Проблемы / проблемы, описанные в вики-странице greg, не могут быть легко решены с помощью простых условных конструкций. lsэто простая команда. Его вывод - это строки. Bash очень хорошо разбирается в строках. Правильное регулярное выражение - это все, что необходимо для безопасного анализа lsвывода.
Yokai
@Yokai Различные версии lsделают разные вещи с забавными / непечатаемыми символами в именах файлов, поэтому нет единого способа преобразовать его вывод в список имен файлов. И, как я уже сказал, на самом деле он не делает ничего полезного: если вы правильно проанализируете выводls -d */ , вы получите то же самое, что и получили бы напрямую */(кроме случаев, когда совпадений нет, и это легко проверить).
Гордон Дэвиссон
Итак, чтобы подвести итог: A lazy sysadmin is a good sysadmin. возможно, мой собственный lsсинтаксический анализ специфичен для той версии, которая у меня есть или к которой я привык, но пока у них не было проблем с дистрибутивами Linux, на которых я их тестировал. Я могу говорить только по опыту.
Ёкай
8
Это будет печатать файлы в этих каталогах построчно.
Ответы:
Было бы это
РЕДАКТИРОВАТЬ: см. Решение Гордона Дэвиссона для более общего ответа (например, если ваши имена файлов содержат специальные символы). Этот ответ - просто исправление синтаксиса.
источник
ARR+=('$(ls -d */)')
функцию для редактирования элементов в массиве, используя одинарные кавычки для работы со специальными символами, чтобы добавить или удалить элементы в него. массив. Одиночные кавычки сохраняют буквальные символы и устраняют необходимость в экранировании, чтобы иметь дело с ними в именах каталогов.declare -a ARR; ARR+=('$(ls -d "$INPUT_DIR"/*)')
возвращает только$(ls -d $INPUT_DIR/*)
ARR+=("$(ls -d */)")
должно сработать. Если не просто дайте мне знать.По возможности следует избегать синтаксического анализа вывода
ls
(см . Вики Грега по этой теме ). Обычно выводls
будет неоднозначным, если в любом из имен файлов есть забавные символы. Также обычно это пустая трата времени. В этом случае, когда вы выполняетеls -d */
, происходит то, что оболочка расширяется*/
до списка подкаталогов (который уже является именно тем, что вам нужно), передает этот список в качестве аргументов вls -d
, который просматривает каждый из них и говорит: «Да, это каталог. хорошо »и распечатывает его (в противоречивом, а иногда и неоднозначном формате). Командаls
не делает ничего полезного!Хорошо, хорошо, он делает одну полезную вещь: если нет подкаталогов,
*/
он останется как есть,ls
будет искать подкаталог с именем «*», но не находить его, печатать сообщение об ошибке, что он не существует (чтобы stderr), а не выводить «* /» (на стандартный вывод).Более простой способ создать массив имен подкаталогов - использовать glob (
*/
), не передавая его вls
. Но чтобы избежать добавления "* /" в массив, если фактических подкаталогов нет, вы должны сначала установить nullglob (опять же, см . Вики Грега ):shopt -s nullglob array=(*/) shopt -u nullglob # Turn off nullglob to make sure it doesn't interfere with anything later echo "${array[@]}" # Note double-quotes to avoid extra parsing of funny characters in filenames
Если вы хотите распечатать сообщение об ошибке при отсутствии подкаталогов, вам лучше сделать это самостоятельно:
if (( ${#array[@]} == 0 )); then echo "No subdirectories found" >&2 fi
источник
/
использовать имя каталога?ls
это простая команда. Его вывод - это строки. Bash очень хорошо разбирается в строках. Правильное регулярное выражение - это все, что необходимо для безопасного анализаls
вывода.ls
делают разные вещи с забавными / непечатаемыми символами в именах файлов, поэтому нет единого способа преобразовать его вывод в список имен файлов. И, как я уже сказал, на самом деле он не делает ничего полезного: если вы правильно проанализируете выводls -d */
, вы получите то же самое, что и получили бы напрямую*/
(кроме случаев, когда совпадений нет, и это легко проверить).A lazy sysadmin is a good sysadmin.
возможно, мой собственныйls
синтаксический анализ специфичен для той версии, которая у меня есть или к которой я привык, но пока у них не было проблем с дистрибутивами Linux, на которых я их тестировал. Я могу говорить только по опыту.Это будет печатать файлы в этих каталогах построчно.
array=(ww/* ee/* qq/*) printf "%s\n" "${array[@]}"
источник