Как я пишу Баш скрипт , который проходит через каждый каталог внутри parent_directory и выполняет в команду в каждом каталоге .
Структура каталогов следующая:
parent_directory (имя может быть любым - не соответствует шаблону)
- 001 (имена каталогов соответствуют этому шаблону)
- 0001.txt (имена файлов следуют этому шаблону)
- 0002.txt
- 0003.txt
- 002
- 0001.txt
- 0002.txt
- 0003.txt
- 0004.txt
- 003
- 0001.txt
количество каталогов неизвестно.
cd "$d"
было бы лучше, если бы он переносился в ситуации, когда подстановочный знак действительно соответствует файлам, имена которых содержат пробелы и / или метасимволы оболочки.for f in foo bar; do cat "$f"/*.txt; done >output
функционально эквивалентенcat foo/*.txt bar/*.txt >output
. Тем не менее,ls
это одна команда, которая выводит немного разные результаты в зависимости от того, как вы передаете ей аргументы; аналогично,grep
или,wc
который выводит относительное имя файла, будет другим, если вы запустите его из подкаталога (но часто вы хотите избежать входа в подкаталог именно по этой причине).Этот ответ, опубликованный Тоддом, мне помог.
find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;
В
\( ! -name . \)
избегает выполнения команды в текущем каталоге.источник
find FOLDER* -maxdepth 0 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;
-exec bash -c 'cd "$0" && pwd' {} \;
поскольку некоторые каталоги содержали одинарные и некоторые двойные кавычки.-mindepth 1
pwd
напрямую?disd(){find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c 'cd "{}" && "$@"' \;}
не работает.Если вы используете GNU
find
, вы можете попробовать-execdir
параметр, например:find . -type d -execdir realpath "{}" ';'
или (согласно комментарию @gniourf_gniourf ):
find . -type d -execdir sh -c 'printf "%s/%s\n" "$PWD" "$0"' {} \;
Примечание: вы можете использовать
${0#./}
вместо,$0
чтобы исправить./
спереди.или более практический пример:
find . -name .git -type d -execdir git pull -v ';'
Если вы хотите включить текущий каталог, это еще проще, используя
-exec
:find . -type d -exec sh -c 'cd -P -- "{}" && pwd -P' \;
или используя
xargs
:find . -type d -print0 | xargs -0 -L1 sh -c 'cd "$0" && pwd && echo Do stuff'
Или аналогичный пример, предложенный @gniourf_gniourf :
find . -type d -print0 | while IFS= read -r -d '' file; do # ... done
В приведенных выше примерах поддерживаются каталоги с пробелами в имени.
Или назначив в массив bash:
dirs=($(find . -type d)) for dir in "${dirs[@]}"; do cd "$dir" echo $PWD done
Измените
.
имя папки на свое. Если вам не нужно запускать рекурсивно, вы можете использоватьdirs=(*)
вместо этого :. В приведенном выше примере не поддерживаются каталоги с пробелами в имени.Итак, как предложил @gniourf_gniourf , единственный правильный способ поместить вывод find в массив без использования явного цикла будет доступен в Bash 4.4 с:
mapfile -t -d '' dirs < <(find . -type d -print0)
Или не рекомендуемый способ (который включает в себя разбор
ls
):ls -d */ | awk '{print $NF}' | xargs -n1 sh -c 'cd $0 && pwd && echo Do stuff'
В приведенном выше примере будет игнорироваться текущий каталог (по запросу OP), но он будет разбит на имена с пробелами.
Смотрите также:
источник
find
в массив без использования явного цикла будет доступен в Bash 4.4 сmapfile -t -d '' dirs < <(find . -type d -print0)
. До тех пор единственный вариант - использовать цикл (или отложить операцию доfind
).dirs
массив; вы могли бы петля наfind
выходе «S (безопасно) , так как:find . -type d -print0 | while IFS= read -r -d '' file; do ...; done
.IFS
,read
, это создает впечатление дополнительной сложности. Придется подумать, может есть способ попроще.IFS
иread
(как вы говорите) стать второй натурой , как вы привыкнете к ним ... они являются частью канонического и идиоматических способов написания сценариев.find . -type d -execdir echo $(pwd)/{} ';'
не делает то, что вы хотите ($(pwd)
расширяется до того,find
как даже выполняется)…Вы можете добиться этого, установив трубопровод, а затем используя
xargs
. Уловка заключается в том, что вам нужно использовать-I
флаг, который заменит подстроку в вашей команде bash подстрокой, переданной каждым изxargs
.ls -d */ | xargs -I {} bash -c "cd '{}' && pwd"
Вы можете заменить
pwd
любую команду, которую хотите выполнить в каждом каталоге.источник
Если папка верхнего уровня известна, вы можете просто написать что-то вроде этого:
for dir in `ls $YOUR_TOP_LEVEL_FOLDER`; do for subdir in `ls $YOUR_TOP_LEVEL_FOLDER/$dir`; do $(PLAY AS MUCH AS YOU WANT); done done
На $ (ИГРАЙТЕ СКОЛЬКО ХОЧЕТЕ); вы можете поместить столько кода, сколько захотите.
Обратите внимание, что я не «cd» ни в одном каталоге.
Привет,
источник
ls
» - вы можете просто сделать этоfor dir in $YOUR_TOP_LEVEL_FOLDER/*
.ls $dir
выражениеfor dir in PARENT/* do test -d "$dir" || continue # Do something with $dir... done
источник
Хотя один лайнер хорош для быстрого и грязного использования, я предпочитаю ниже более подробную версию для написания скриптов. Это шаблон, который я использую, он заботится о многих крайних случаях и позволяет вам писать более сложный код для выполнения в папке. Вы можете написать свой код на bash в функции dir_command. Ниже dir_coomand в качестве примера реализует пометку каждого репозитория в git. Остальная часть скрипта вызывает dir_command для каждой папки в каталоге. Также включен пример перебора только заданного набора папок.
#!/bin/bash #Use set -x if you want to echo each command while getting executed #set -x #Save current directory so we can restore it later cur=$PWD #Save command line arguments so functions can access it args=("$@") #Put your code in this function #To access command line arguments use syntax ${args[1]} etc function dir_command { #This example command implements doing git status for folder cd $1 echo "$(tput setaf 2)$1$(tput sgr 0)" git tag -a ${args[0]} -m "${args[1]}" git push --tags cd .. } #This loop will go to each immediate child and execute dir_command find . -maxdepth 1 -type d \( ! -name . \) | while read dir; do dir_command "$dir/" done #This example loop only loops through give set of folders declare -a dirs=("dir1" "dir2" "dir3") for dir in "${dirs[@]}"; do dir_command "$dir/" done #Restore the folder cd "$cur"
источник
Я не понимаю, что такое форматирование файла, так как вы хотите только перебирать папки ... Вы ищете что-то вроде этого?
cd parent find . -type d | while read d; do ls $d/ done
источник
ты можешь использовать
для рекурсивного поиска всех файлов / каталогов в текущем каталоге
Затем вы можете передать вывод команде xargs следующим образом
find . | xargs 'command here'
источник
for p in [0-9][0-9][0-9];do ( cd $p for f in [0-9][0-9][0-9][0-9]*.txt;do ls $f; # Your operands done ) done
источник
cd
в подоболочке.cd
поэтому этот код фактически не делает ничего полезного.