2012-05-09 8 views
163

Czy ktoś mógłby podać kod, aby wykonać następujące czynności: Załóżmy, że istnieje katalog plików, z których wszystkie muszą być uruchamiane przez program. Program wyprowadza wyniki na standardowe wyjście. Potrzebuję skryptu, który przejdzie do katalogu, wykona polecenie dla każdego pliku i połączy wyjście w jeden duży plik wyjściowy.Skrypt Bash do wykonania polecenia dla wszystkich plików w katalogu

Na przykład, aby uruchomić polecenie na 1 plik:

$ cmd [option] [filename] > results.out 
+3

Chciałbym dodać do pytania. Czy można to zrobić za pomocą xargs? np. 'ls | xargs cmd [opcje] {nazwy plików umieszczane tutaj automatycznie przez xargs} [więcej argumentów]> results.out' –

+0

Może, ale prawdopodobnie [nie chcesz używać 'ls'] (http: //mywiki.wooledge. org/ParsingLs) do napędu 'xargs'. Jeśli 'cmd' jest w ogóle napisane kompetentnie, być może możesz po prostu zrobić' cmd '. – tripleee

Odpowiedz

244

Poniższy kod bash przejdzie $ file dowodzić gdzie $ plik będzie reprezentować każdy plik w/dir

for file in /dir/* 
do 
    cmd [option] "$file" >> results.out 
done 

Przykład

[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 
+13

Jeśli w'/dir/'nie ma plików, to pętla nadal działa jednokrotnie z wartością '*' dla' $ file', co może być niepożądane. Aby tego uniknąć, włącz opcję nullglob na czas trwania pętli. Dodaj tę linię przed pętlą 'shopt -s nullglob' i tą linią po pętli' shopt -u nullglob #reset nullglob z powrotem do normalnego stanu domyślnego'. –

+29

+1, I to kosztowało mnie całą moją kolekcję tapet. wszyscy po mnie, używaj podwójnych cytatów. "$ file" – Behrooz

+0

Jeśli plik wyjściowy jest taki sam wewnątrz pętli, znacznie skuteczniejsze jest przekierowanie poza pętlę 'done> results.out' (i prawdopodobnie wtedy możesz zastąpić zamiast append, jak zakładałem tutaj). – tripleee

112

Jak o tym:

find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out 
  • -maxdepth 1 Argument zapobiega znaleźć z rekurencyjnie schodząc do wszelkich podkatalogów. (Jeśli chcesz, aby takie zagnieżdżone katalogi zostały przetworzone, możesz to pominąć.)
  • -type -f określa, że ​​przetwarzane będą tylko zwykłe pliki.
  • -exec cmd option {} informuje go uruchomić cmd z określonym option dla każdego pliku znaleziony, z pliku zastąpiono {}
  • \; oznacza koniec polecenia.
  • Wreszcie, wyjście ze wszystkich poszczególnych cmd egzekucji jest przekierowywany do results.out

Jednakże, jeśli dbasz o kolejności, w której pliki są przetwarzane, może być lepiej pisania pętlę. Myślę, że find przetwarza pliki w kolejności i-węzłów (chociaż mógłbym się mylić co do tego), co może nie być tym, czego potrzebujesz.

+1

To jest poprawny sposób przetwarzania plików. Korzystanie z pętli for jest podatne na błędy z wielu powodów. Sortowanie można również wykonać za pomocą innych poleceń, takich jak 'stat' i' sort', które oczywiście zależą od kryteriów sortowania. – tuxdna

+0

gdybym chciał uruchomić dwa polecenia, w jaki sposób połączyć je po opcji '-exec'? Czy muszę zawijać je w pojedyncze cytaty lub coś w tym stylu? – frei

+0

'find' jest zawsze najlepszą opcją, ponieważ możesz filtrować według wzorca nazwy pliku za pomocą opcji' -name' i możesz to zrobić za pomocą pojedynczego polecenia. –

22

robię to na moim Raspberry Pi z wiersza poleceń za pomocą polecenia:

for i in *;do omxplayer "$i";done 
1

Musiałem skopiować wszystkie pliki .md NumerKopiiZapasowej z jednego katalogu do drugiego, więc oto, co zrobiłem.

for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done

co jest dość trudne do odczytania, więc umożliwia rozbicie go.

pierwszy cd do katalogu z plikami,

for i in **/*.md; dla każdego pliku w swojej strukturze

mkdir -p ../docs/"$i" uczynić ten katalog w folderze docs poza folderu zawierającego pliki. Który tworzy dodatkowy folder o tej samej nazwie jak ten plik.

rm -r ../docs/"$i" usunąć dodatkowy folder, który jest tworzony w wyniku mkdir -p

cp "$i" "../docs/$i" Kopiuj rzeczywista plików

echo "$i -> ../docs/$i" Echo co zrobiłeś

; done żyli długo i szczęśliwie

1

Jeden szybki i brudnym sposobem, który dostaje pracę, jest czasami:

Na przykład, aby wybrać liczbę wierszy w wszystkich plików w bieżącym katalogu, można zrobić:

find . | xargs wc -l