Как получить список файлов в каталоге в сценарии оболочки?

Я пытаюсь получить содержимое каталога с помощью сценария оболочки.

Мой сценарий:

for entry in `ls $search_dir`; do
    echo $entry
done

где $search_dir - относительный путь. Однако $search_dir содержит много файлов с пробелами в именах. В этом случае этот сценарий не выполняется должным образом.

Я знаю, что могу использовать for entry in *, но это будет работать только для моего текущего каталога.

Я знаю, что могу перейти в этот каталог, использовать for entry in *, а затем вернуться, но моя конкретная ситуация не позволяет мне сделать это.

У меня есть два относительных пути $search_dir и $work_dir, и я должен работать над обоими одновременно, читая их, создавая / удаляя в них файлы и т. Д.

Так что мне теперь делать?

PS: я использую bash.


person jrharshath    schedule 13.03.2010    source источник


Ответы (7)


Это способ сделать это, где мне проще понять синтаксис:

yourfilenames=`ls ./*.txt`
for eachfile in $yourfilenames
do
   echo $eachfile
done

./ - текущий рабочий каталог, но его можно заменить любым путем
*.txt возвращает something.txt
Вы можете легко проверить, что будет указано, набрав команду ls прямо в терминал.

По сути, вы создаете переменную yourfilenames, содержащую все, что команда list возвращает в виде отдельного элемента, а затем просматриваете ее в цикле. Цикл создает временную переменную eachfile, которая содержит единственный элемент переменной, которую он просматривает, в данном случае имя файла. Это не обязательно лучше, чем другие ответы, но я считаю его интуитивно понятным, потому что я уже знаком с командой ls и синтаксисом цикла for.

person rrr    schedule 27.04.2017
comment
Это нормально работает для быстрого, неформального сценария или однострочного скрипта, но он сломается, если имя файла содержит символы новой строки, в отличие от решений на основе глобусов. - person Soren Bjornstad; 03.09.2018
comment
@SorenBjornstad спасибо за совет! Я не знал, что в именах файлов разрешены символы новой строки - в каких файлах они могут быть? Типа, такое часто случается? - person rrr; 04.09.2018
comment
Новые строки в именах файлов по этой причине являются злом, и, насколько я знаю, нет законных причин для их использования. Я никогда не видел ни одного в дикой природе. Тем не менее, вполне возможно злонамеренно создать имена файлов с символами новой строки, чтобы воспользоваться этим. (Например, представьте себе каталог, содержащий файлы A, B и C. Вы создаете файлы с именами B\nC и D, а затем решаете удалить их. Программное обеспечение, которое не поддерживает это право, может в конечном итоге удалить уже существующие файлы B и C, даже если у вас не было на это разрешения.) - person Soren Bjornstad; 05.09.2018
comment
mywiki.wooledge.org/ParsingLs объясняет большое количество подводных камней, связанных с этим подходом. Вы никогда не должны использовать ls в скриптах. В любом случае это глупо; оболочка уже расширила подстановочный знак к моменту выполнения ls. - person tripleee; 16.12.2020

Другие ответы здесь великолепны и отвечают на ваш вопрос, но это лучший результат Google для «bash получить список файлов в каталоге» (который я искал, чтобы сохранить список файлов), поэтому я подумал, что опубликую ответ на эту проблему:

ls $search_path > filename.txt

Если вам нужен только определенный тип (например, любые файлы .txt):

ls $search_path | grep *.txt > filename.txt

Обратите внимание, что $ search_path не является обязательным; ls> filename.txt сделает текущий каталог.

person tegan    schedule 23.10.2014
comment
Не нужно использовать grep для получения только файлов .txt: `ls $ search_path / *. Txt› filename.txt '. Но что еще более важно, не следует использовать вывод команды ls для анализа имен файлов. - person Victor Zamanian; 07.06.2017
comment
@VictorZamanian, не могли бы вы объяснить, почему мы не должны использовать вывод ls для анализа имен файлов? Не слышал об этом раньше. - person samurai_jane; 09.02.2019
comment
@samurai_jane По этой теме можно найти много ссылок, но вот один из первых результатов поиска: mywiki.wooledge.org/ ParsingLs. Я даже видел здесь вопрос о SO, в котором утверждалось, что причины отказа от синтаксического анализа вывода ls были BS, и был очень подробный об этом. Но ответы по-прежнему утверждали, что это плохая идея. Посмотрите: unix.stackexchange.com/questions/128985/ - person Victor Zamanian; 09.02.2019

$ pwd; ls -l
/home/victoria/test
total 12
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  a
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  b
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  c
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:32 'c d'
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:31  d
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32  dir_a
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32  dir_b
-rw-r--r-- 1 victoria victoria    0 Apr 23 11:32 'e; f'

$ find . -type f
./c
./b
./a
./d
./c d
./e; f

$ find . -type f | sed 's/^\.\///g' | sort
a
b
c
c d
d
e; f

$ find . -type f | sed 's/^\.\///g' | sort > tmp

$ cat tmp
a
b
c
c d
d
e; f

Варианты

$ pwd
/home/victoria

$ find $(pwd) -maxdepth 1 -type f -not -path '*/\.*' | sort
/home/victoria/new
/home/victoria/new1
/home/victoria/new2
/home/victoria/new3
/home/victoria/new3.md
/home/victoria/new.md
/home/victoria/package.json
/home/victoria/Untitled Document 1
/home/victoria/Untitled Document 2

$ find . -maxdepth 1 -type f -not -path '*/\.*' | sed 's/^\.\///g' | sort
new
new1
new2
new3
new3.md
new.md
package.json
Untitled Document 1
Untitled Document 2

Примечания:

  • .: текущая папка
  • удалить -maxdepth 1 для рекурсивного поиска
  • -type f: искать файлы, а не каталоги (d)
  • -not -path '*/\.*': не возвращать .hidden_files
  • sed 's/^\.\///g': удалить добавленный ./ из списка результатов
person Victoria Stuart    schedule 23.04.2019

Принятый ответ не вернет префикс файлов с расширением. Для этого используйте

for entry in "$search_dir"/* "$search_dir"/.[!.]* "$search_dir"/..?*
do
  echo "$entry"
done
person TrevTheDev    schedule 19.03.2019

Вот еще один способ перечисления файлов внутри каталога (с использованием другого инструмента, не столь эффективного, как некоторые другие ответы).

cd "search_dir"
for [ z in `echo *` ]; do
    echo "$z"
done

echo * Выводит все файлы текущего каталога. Цикл for перебирает каждое имя файла и выводит его на стандартный вывод.

Кроме того, если вы ищете каталоги внутри каталога, поместите это в цикл for:

if [ test -d $z ]; then
    echo "$z is a directory"
fi

test -d проверяет, является ли файл каталогом.

person SnoopDogg    schedule 04.12.2018
comment
for [ z - синтаксическая ошибка. if [ test глупо и неправильно. Отсутствие цитирования "$z" является ошибкой цитирования. - person tripleee; 16.12.2020
comment
Пожалуйста, объясни. Я успешно запустил код, когда написал ответ. Если собираешься некропостить, по крайней мере будь полезным. - person SnoopDogg; 17.12.2020
comment
Что объяснять? Если вы тестировали это тогда, вы определенно не использовали стандартную оболочку. Я уже указывал на ошибки, и нетрудно найти, как выглядит правильный синтаксис, даже из некоторых других ответов здесь. Но посмотрите эту демонстрацию: ideone.com/ERcu2c и поделитесь ею, сколько душе угодно. - person tripleee; 17.12.2020
comment
Если вы думаете, что это не имеет значения, потому что он старый, вы не понимаете, как работает Stack Overflow. На это регулярно - вероятно, ежедневно - ссылаются как на канонический ответ для новых пользователей, которые публикуют дубликаты этого распространенного вопроса, но также получают, вероятно, в 100 раз больше трафика из поисков Google. - person tripleee; 17.12.2020

person    schedule
comment
Вы можете объяснить, почему for entry in "$search_dir/*" не работает? Почему нам нужно поместить /* вне кавычек? - person mrgloom; 03.03.2016
comment
@mrgloom: потому что вам нужно позволить оболочке использовать подстановочный знак. - person Ignacio Vazquez-Abrams; 03.03.2016
comment
не будет find быстрее? - person Alexej Magura; 15.03.2017
comment
@AlexejMagura: find - это отдельный процесс. Глобус происходит в оболочке. - person Ignacio Vazquez-Abrams; 15.03.2017
comment
Решение дает полный путь. Что, если я просто хочу перечислить то, что находится в текущем каталоге? - person ThatsRightJack; 23.07.2017
comment
Просто опустите путь. - person Ignacio Vazquez-Abrams; 23.07.2017
comment
@mrgloom, если вы хотите, вы можете добиться этого с помощью for entry in "${search_dir}/*" - person funilrys; 12.08.2017
comment
он не работает, если файл разделен пробелами (рассматривайте каждый как запись) - person CallMeLoki; 16.01.2018
comment
на MacO скобки не нужны - просто напишите: для записи в ~ / gcloud_installs / * - person Agile Bean; 16.06.2018
comment
Это не работает рекурсивно. Для рекурсивного решения лучше find. См. Этот ответ stackoverflow.com/a/55817578/1343917 - person Dmitry Gonchar; 08.05.2019
comment
Это не работает (в bash с настройками по умолчанию), если папка пуста или если некоторые файлы начинаются с точки. - person Martin Jambon; 21.07.2020
comment
Есть ли способ реализовать | grep *.txt из ответа ниже на этот фрагмент? - person Georodin; 28.07.2020
comment
@ Georodin Просто используйте "$search_dir"/*.txt, если это то, что вам нужно. - person tripleee; 16.12.2020
comment
@Anish B: Прекратите вандализировать исходный пост. Ответ был правильным, как написано - person Inian; 16.12.2020
comment
@AnishB .: Нет, ответ как он был написан, должен работать нормально для имени каталога, назначенного переменной search_dir - person Inian; 16.12.2020
comment
@AnishB .: Если у вас возникла проблема с попыткой, значит, что-то не так с вашей стороны. Предложите задать новый вопрос, чтобы решить эту проблему, вместо того, чтобы неправильно изменять высоко оцененный ответ (также проверьте, находится ли ваш * за пределами двойных кавычек) - person Inian; 16.12.2020
comment
Нет ничего плохого в цитировании переменной search_dir. См. Когда заключать переменную оболочки в кавычки?, т.е. для защиты от имен каталогов, содержащих пробелы - person Inian; 16.12.2020
comment
@Inian, у меня проблема. Да ты прав. - person Anish B.; 16.12.2020

person    schedule
comment
Я знаю, что это довольно давно, но я не могу получить последнюю команду xargs -0 -i echo "{}", не могли бы мне немного объяснить? В частности, что делает -i echo "{}" часть? Также я прочитал со страницы man, что -i теперь устарел, и мы должны использовать -I insted. - person drkg4b; 05.10.2015
comment
-i заменяет {} аргументом. - person Noel Yap; 05.10.2015
comment
Спасибо! Это полезно, в том числе и для медлительных людей вроде меня. Я думаю, что {} - это строка, которая заменяется совпадениями командой find. - person drkg4b; 06.10.2015
comment
Это то, что заменяется на xargs, а не на find. - person Noel Yap; 06.10.2015
comment
Я обновил ответ, чтобы использовать -I. Спасибо за предупреждение об устаревании -i. - person Noel Yap; 06.10.2015
comment
почему вы используете xargs? по умолчанию find печатает то, что находит ... вы можете удалить все из -print0. - person gniourf_gniourf; 06.10.2015
comment
Это не будет хорошо обрабатывать записи файлов с пробелами. - person Noel Yap; 07.09.2018