Jak napisać skrypt bash, który przechodzi przez każdego katalogu wewnątrz parent_directory i wykonuje się polecenia w każdym katalogu .
Struktura katalogów jest następująca:
katalog_nadrzędny (nazwa może być dowolna - nie podąża za wzorcem)
- 001 (nazwy katalogów są zgodne z tym wzorcem)
- 0001.txt (nazwy plików są zgodne z tym wzorcem)
- 0002.txt
- 0003.txt
- 002
- 0001.txt
- 0002.txt
- 0003.txt
- 0004.txt
- 003
- 0001.txt
liczba katalogów jest nieznana.
cd "$d"
byłoby lepsze, ponieważ przenosi się do sytuacji, w których symbol wieloznaczny pasuje do plików, których nazwy zawierają białe spacje i / lub metaznaki powłoki.for f in foo bar; do cat "$f"/*.txt; done >output
jest funkcjonalnie równoważny zcat foo/*.txt bar/*.txt >output
. Jednakls
jest jedno polecenie, które daje nieco inny wynik w zależności od tego, jak przekazujesz mu argumenty; podobnie, agrep
lub,wc
który wypisuje względną nazwę pliku, będzie inny, jeśli uruchomisz go z podkatalogu (ale często chcesz uniknąć wchodzenia do podkatalogu właśnie z tego powodu).Ta odpowiedź wysłana przez Todda pomogła mi.
W
\( ! -name . \)
unika wykonywania polecenia w bieżącym katalogu.źródło
find FOLDER* -maxdepth 0 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;
-exec bash -c 'cd "$0" && pwd' {} \;
ponieważ niektóre katalogi zawierały pojedyncze cudzysłowy, a niektóre podwójne cudzysłowy.-mindepth 1
pwd
bezpośrednio?disd(){find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c 'cd "{}" && "$@"' \;}
nie działa.Jeśli używasz GNU
find
, możesz wypróbować-execdir
parametr, np:lub (zgodnie z komentarzem @gniourf_gniourf ):
Uwaga: można użyć
${0#./}
zamiast$0
mocowania./
z przodu.lub bardziej praktyczny przykład:
Jeśli chcesz dołączyć bieżący katalog, jest to jeszcze prostsze, używając
-exec
:lub używając
xargs
:Lub podobny przykład sugerowany przez @gniourf_gniourf :
Powyższe przykłady obsługują katalogi ze spacjami w nazwie.
Lub przypisując do tablicy bash:
Zmień
.
na określoną nazwę folderu. Jeśli nie potrzebujesz uruchamiać rekurencyjnie, możesz użyć:dirs=(*)
zamiast. Powyższy przykład nie obsługuje katalogów ze spacjami w nazwie.Tak więc, jak zasugerował @gniourf_gniourf , jedyny właściwy sposób umieszczenia wyniku find w tablicy bez użycia jawnej pętli będzie dostępny w Bash 4.4 z:
Lub nie jest to zalecany sposób (który obejmuje analizę
ls
):Powyższy przykład zignorowałby bieżący katalog (zgodnie z żądaniem OP), ale zepsuje nazwy ze spacjami.
Zobacz też:
źródło
find
w tablicy bez użycia jawnej pętli będzie dostępny w Bash 4.4 zmapfile -t -d '' dirs < <(find . -type d -print0)
. Do tego czasu jedyną opcją jest użycie pętli (lub odroczenie operacjifind
).dirs
tablica nie jest potrzebna ; mógłbyś pętla nafind
„wyjście S (bezpiecznie) tak:find . -type d -print0 | while IFS= read -r -d '' file; do ...; done
.IFS
,read
, daje wrażenie dodatkowej złożoności. Muszę się nad tym zastanowić, może jest na to prostszy sposób.IFS
iread
(jak mówisz) stają się drugą naturą, gdy się do nich przyzwyczaisz… są częścią kanonicznych i idiomatycznych sposobów pisania scenariuszy.find . -type d -execdir echo $(pwd)/{} ';'
nie robi tego, co chcesz ($(pwd)
jest rozwijane, zanimfind
zostanie nawet wykonane)…Możesz to osiągnąć przez orurowanie, a następnie za pomocą
xargs
. Chwyt polega na tym, że musisz użyć-I
flagi, która zamieni podciąg w twoim poleceniu bash na podciąg przekazany przez każdy zxargs
.Możesz zamienić na
pwd
dowolne polecenie, które chcesz wykonać w każdym katalogu.źródło
Jeśli znany jest folder najwyższego poziomu, możesz po prostu napisać coś takiego:
Na $ (GRAJ JAK TYLKO CHCESZ); możesz umieścić tyle kodu, ile chcesz.
Zauważ, że nie "cd" w żadnym katalogu.
Twoje zdrowie,
źródło
ls
” - możesz po prostu to zrobićfor dir in $YOUR_TOP_LEVEL_FOLDER/*
.ls $dir
wyrażeniaźródło
Podczas gdy jeden liner jest dobry do szybkiego i brudnego użycia, wolę poniżej bardziej rozwlekłą wersję do pisania skryptów. To jest szablon, którego używam, który zajmuje się wieloma skrajnymi przypadkami i umożliwia pisanie bardziej złożonego kodu do wykonania w folderze. Możesz napisać swój kod basha w funkcji dir_command. Poniżej dir_coomand implementuje tagowanie każdego repozytorium w git jako przykład. Reszta skryptu wywołuje dir_command dla każdego folderu w katalogu. Dołączono również przykład iteracji po tylko podanym zestawie folderów.
źródło
Nie rozumiem, o co chodzi z formatowaniem pliku, ponieważ chcesz tylko iterować po folderach ... Szukasz czegoś takiego?
źródło
możesz użyć
aby przeszukać wszystkie pliki / katalogi w bieżącym katalogu cyklicznie
Następnie możesz potokować wyjście polecenie xargs w ten sposób
źródło
źródło
cd
w podpowłoce.cd
więc ten kod nie robi nic pożytecznego.