Ar putea cineva vă rugăm să furnizați codul pentru a face următoarele: Presupun că există un director de fișiere, toate de care trebuie să fi rulat printr-un program. Programul ieșiri rezultatele la ieșirea standard. Am nevoie de un script care va merge într-un director, executați comanda de pe fiecare fișier, și concat ieșire într-un fișier de ieșire.
De exemplu, pentru a rula comanda pe 1 fișier:
$ cmd [option] [filename] > results.out
Următoarele bash cod va trece $fișier pentru a comanda în cazul în care fișierul va reprezenta fiecare fișier în /dir
for file in /dir/*
do
cmd [option] "$file" >> results.out
done
Exemplu
[email protected] ~/foo $ touch foo.txt bar.txt baz.txt
[email protected] ~/foo $ for i in *.txt; do echo "hello $i"; done
hello bar.txt
hello baz.txt
hello foo.txt
Ce zici de asta:
find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out
-maxdepth 1
argument previne găsi din recursiv descendent în
orice subdirectoare. (Dacă vrei, cum ar imbricate directoare pentru a obține prelucrate, puteți omite acest lucru.)-tip -f
specifică faptul că doar simplu fișierele vor fi prelucrate.-exec cmd opțiunea {}
spune-l pentru a rula " cmd "specificate" opțiunea " pentru fiecare fișier găsit, cu numele substituit pentru {}
\;
denotă sfârșitul comenzii.rezultatele.out
Cu toate acestea, dacă vă pasă de ordinea în care fișierele sunt prelucrate, ai ar fi mai bine scris-o buclă. Cred că "găsi" procese fișierele în inode ordine (deși am putea fi greșit), care nu poate fi ceea ce vrei.
Nu este nevoie pentru a copia toate .md fișiere dintr-un director în altul, deci, aici este ceea ce am făcut.
pentru că în **/*.md;face mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done
Care este destul de greu de citit, deci, vă permite să-l rupe în jos.
primul cd în directorul cu fișiere,
`pentru că în */.md; pentru fiecare fișier în model
mkdir -p ../docs/"$i"
face acel director într-un docs afara de folderul care conține fișierele. Care creează un plus de dosar cu același nume ca fișierul.
rm -r ../docs/"$i"
elimina extra folder care este creat ca urmare a mkdir -p
cp "$i" "../docs/$i"
Copia fișierul în sine
echo "$i -> ../docs/$i"
Echo ce ai facut
`; făcut pentru a Trăi până la adânci bătrâneți
Am constatat că funcționează bine cu Jim Lewis's a răspunde trebuie doar să adăugați un pic de genul asta:
$ export DIR=/path/dir && cd $DIR && chmod -R +x *
$ find . -maxdepth 1 -type f -name '*.sh' -exec {} \; > results.out
Dacă vrei să execute în ordine de sortare, se modifica astfel:
$ export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -maxdepth 2 -type f -name '*.sh' | sort | bash > results.out
Doar un exemplu, acest lucru va executa cu următoarele ordine:
bash: 1: ./assets/main.sh
bash: 2: ./builder/clean.sh
bash: 3: ./builder/concept/compose.sh
bash: 4: ./builder/concept/market.sh
bash: 5: ./builder/concept/services.sh
bash: 6: ./builder/curl.sh
bash: 7: ./builder/identity.sh
bash: 8: ./concept/compose.sh
bash: 9: ./concept/market.sh
bash: 10: ./concept/services.sh
bash: 11: ./product/compose.sh
bash: 12: ./product/market.sh
bash: 13: ./product/services.sh
bash: 14: ./xferlog.sh
Dacă vrei să execute în adâncime nelimitat de anumite condiții, puteți folosi acest lucru:
export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -type f -name '*.sh' | sort | bash > results.out
apoi a pus pe partea de sus a fiecărei fișiere în copil directoare de genul asta:
#!/bin/bash
[[ "$(dirname `pwd`)" == $DIR ]] && echo "Executing `realpath $0`.." || return
și undeva în corpul de părinte fișier:
if <a condition is matched>
then
#execute child files
export DIR=`pwd`
fi
Acceptat/high-au votat răspunsuri sunt mari, dar ele sunt lipsite de câteva nitty-gritty detalii. Acest post se referă la cazurile pe cum să se ocupe mai bine atunci când shell calea-nume de expansiune (glob) nu reușește, atunci când numele fișierelor conțin liniile/simboluri de bord și se deplasează comanda de ieșire de re-direcția de ieșire din buclă de-atunci când scrie rezultatele într-un fișier.
Atunci când rulează shell glob de expansiune folosind *
există o posibilitate de extindere a eșua în cazul în care există no fișierele prezente în directorul și ne-a extins glob șir va fi trecut la comandă pentru a fi rulat, care ar putea avea rezultate nedorite. Anii bash shell oferă un extins shell opțiune pentru acest lucru, folosind
nullglob`. Deci bucla, practic, devine, după cum urmează în directorul care conține fișierele dvs.
shopt -s nullglob
for file in ./*; do
cmdToRun [option] -- "$file"
done
Acest lucru vă permite să în condiții de siguranță de ieșire din buclă atunci când expresia ./*
nu orice fișiere ( dacă directorul este gol)
sau într-un mod compatibil POSIX (`nullglob "este" bash specifice)
for file in ./*; do
[ -f "$file" ] || continue
cmdToRun [option] -- "$file"
done
Acest lucru vă permite să mergeți în interiorul buclei, atunci când expresia nu o dată și starea [ -f "$file" ]
verifica dacă onu-a extins string ./*
este un nume de fișier valid în acel director, care nu't fi. Deci, în această stare de eșec, folosind "continue" ne cv-ul înapoi la "pentru" buclă care a câștigat't rula ulterior.
Rețineți, de asemenea, utilizarea de --
doar înainte de a trece numele fișierului argument. Acest lucru este necesar pentru că, după cum sa menționat anterior, coajă de nume de fișiere poate conține linii oriunde in nume de fișier. Unele comenzi shell interpreta și de a le trata ca o comandă opțiune atunci când numele sunt nu citat în mod corespunzător și execută comanda gândesc că dacă steagul este furnizat.
La --
semnale de la sfârșitul de opțiuni de linie de comandă în acest caz, ceea ce înseamnă, comanda ar trebui't analiza orice siruri de caractere dincolo de acest punct ca comanda steaguri, ci doar ca nume de fișiere.
Dublu-cu referire la nume de fișiere în mod corespunzător rezolvă cazurile când numele conține glob de caractere sau alb-spații. Dar *nix nume de fișiere pot, de asemenea, conține liniile noi în ele. Deci, avem de-limită de nume de fișiere cu singurul personaj care nu poate fi parte a unui nume de fișier valid - la byte null (\0
). Din bash
folosește intern " C " stil de siruri de caractere în care null bytes sunt folosite pentru a indica sfârșitul șirului, este candidatul potrivit pentru acest lucru.
Deci, folosind "printf" opțiune de shell pentru a delimita fișierele cu această NULL byte folosind -d
posibilitatea de a "citi" comanda, putem face mai jos
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done
Anii nullglob
si "printf" sunt înfășurate în jurul (..)
ceea ce înseamnă că sunt, practic, a alerga într-un sub-shell (copil shell), pentru a evita nullglob
opțiunea de a reflecta asupra părinte shell, odată ce comanda ieșirile. La -d ''
opțiunea de a "citi" comanda nu este POSIX compliant, deci are nevoie de un bash shell pentru ca acest lucru să fie făcut. Folosind "găsi" comanda acest lucru poate fi făcut ca
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)
Pentru a "găsi" implementări că don't de sprijin `-print0 (altele decât GNU și FreeBSD implementari), acest lucru poate fi emulat folosind "printf"
find . -maxdepth 1 -type f -exec printf '%s\0' {} \; | xargs -0 cmdToRun [option] --
Un alt fix important este de a muta re-direcția de ieșire din buclă de-a reduce un număr mare de fișiere I/O. atunci Când este utilizat în interiorul buclei, shell-ul trebuie să execute sistem de apeluri de două ori pentru fiecare iterație a pentru-buclă, o dată pentru deschiderea și o dată pentru închiderea descriptorului de fișier asociat cu fișierul. Acest lucru va deveni o sticla de gât pe performanță pentru a rula mare de iterații. Recomandat sugestie ar fi să-l mute în afara buclei.
Extinderea codul de mai sus cu aceasta stabilește, ai putea face
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done > results.out
care va pune practic conținutul de comanda pentru fiecare iterație a fișierului de intrare la stdout și atunci când bucla se termină, deschideți fișierul țintă o dată pentru a scrie conținutul stdout și salvarea. Echivalentul "găsi" versiune a aceluiași ar fi
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out
Bazat pe @Jim Lewis's de abordare:
Aici este o soluție rapidă, folosind "găsi" și, de asemenea, sortarea fișierelor după data lor de modificare:
$ find directory/ -maxdepth 1 -type f -print0 | \
xargs -r0 stat -c "%y %n" | \
sort | cut -d' ' -f4- | \
xargs -d "\n" -I{} cmd -op1 {}
Pentru sortare se vedea:
http://www.commandlinefu.com/commands/view/5720/find-files-and-list-them-sorted-by-modification-time