Як призначити ls масиву в Linux Bash?


Відповіді:


109

Це було б це

array=($(ls -d */))

EDIT: Дивіться рішення Гордона Девіссона для більш загальної відповіді (тобто, якщо ваші імена файлів містять спеціальні символи). Ця відповідь - це просто корекція синтаксису.


14
Це буде працювати некоректно, якщо імена каталогів містять пробіли.
Чепнер

1
Для того, щоб вирішити проблему з пробілами або спеціальними символами, спочатку оголосіть масив без будь-яких значень, а потім використовуйте вбудований ARR+=('$(ls -d */)')для редагування елементів у масиві, одночасно використовуючи одинарні лапки для роботи зі спеціальними символами, щоб додати або видалити елементи до цього масив. Одинарні лапки зберігають буквальні символи та усувають будь-яку необхідність екранування для роботи з ними в іменах каталогів.
Йокай

@Yokai Ваша пропозиція звучить чудово, але не працювала для мене на Ubuntu 16.04 або MacO. Bash розширює код між одинарними лапками таким чином: declare -a ARR; ARR+=('$(ls -d "$INPUT_DIR"/*)')повертається$(ls -d $INPUT_DIR/*)
Agile Bean

1
Моя помилка. Це мали бути подвійні лапки, щоб заміну команди можна було розширити. ARR+=("$(ls -d */)")повинні працювати. Якщо не просто дайте мені знати.
Йокай

2
@Yokai, який додає лише один елемент у загальній складності (з купою нових рядків), а не один елемент в каталог.
Чарльз Даффі

76

По можливості, слід уникати розбору результатів ls(див . Вікі Грега з цього приводу ). В основному, результат lsбуде неоднозначним, якщо в будь-якому з імен файлів є смішні символи. Це також зазвичай втрата часу. У цьому випадку, під час виконання ls -d */, відбувається те, що оболонка розширюється */до списку підкаталогів (а це вже саме те, що ви хочете), передає цей список як аргументи ls -d, який переглядає кожен із них, каже "так, це каталог все в порядку "і друкує його (у суперечливому, а іноді неоднозначному форматі). lsКоманда не робить нічого корисного!

Ну, добре, він робить одну корисну справу: якщо немає підкаталогів, */залишиться як є, lsбуде шукати підкаталог із назвою "*", а не знаходити, друкувати повідомлення про помилку, що його не існує (до stderr), а не друкувати "* /" (для stdout).

Чистіший спосіб створити масив імен підкаталогів - використовувати 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

2
Дякую за ваш коментар, хоча він і не позначений як відповідь, він був цілком інформативним, і я ціную його.
Jake H

Що робити, якщо ви не хочете /вказувати ім’я в каталозі?
shinzou

Проблеми / проблеми, викладені у вікі greg, - це не речі, з якими неможливо легко вирішити за допомогою простих умовних конструкцій. lsце проста команда. Вихід - це рядки. Bash надмірно добре розбирає рядки. Правильний регулярний вираз - це все, що потрібно для безпечного аналізу lsвихідних даних.
Йокай

@Yokai Різні версії lsроблять різні речі із забавними / недрукованими символами в іменах файлів, тому немає послідовного способу проаналізувати його результати у списку імен файлів. І як я вже казав, насправді це не робить нічого корисного: якщо ви правильно проаналізували висновок ls -d */, ви отримаєте абсолютно те саме, що отримали б безпосередньо */(крім випадків, коли немає збігів, і це легко перевірити).
Гордон Девіссон,

Отже, резюмуємо: A lazy sysadmin is a good sysadmin.Можливо, мій власний lsсинтаксичний аналіз стосується тієї версії, яка у мене є, або до якої я звик, але до цих пір у них не було проблем з дистрибутивами Linux, на яких я їх тестував. Я можу говорити лише з досвіду.
Йокай

7

Це друкувало б файли в цих каталогах, рядок за рядком.

array=(ww/* ee/* qq/*)
printf "%s\n" "${array[@]}"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.