Chciałbym uruchomić:
./a.out < x.dat > x.ans
dla każdego * .dat pliku w katalogu A .
Jasne, można to zrobić za pomocą skryptu bash / python / cokolwiek, ale lubię pisać seksowne, jedno-liniowe. Wszystko, co mogłem osiągnąć to (wciąż bez żadnego standardowego):
ls A/*.dat | xargs -I file -a file ./a.out
Ale -a w xargs nie rozumie „pliku” replace-str.
Dziękuje Ci za pomoc.
io-redirection
xargs
Nikolay Vyahhi
źródło
źródło
Odpowiedzi:
Przede wszystkim nie należy używać
ls
danych wyjściowych jako listy plików . Użyj rozszerzenia powłoki lubfind
. Poniżej przedstawiono potencjalne konsekwencje niewłaściwego użycia ls + xargs i przykład prawidłowegoxargs
użycia.1. Prosty sposób: dla pętli
Jeśli chcesz przetworzyć tylko pliki poniżej
A/
, wystarczy zwykłafor
pętla:2. pre1 Dlaczego nie
ls | xargs
?Oto przykład tego, jak złe rzeczy mogą włączyć w przypadku korzystania
ls
zxargs
do pracy. Rozważ następujący scenariusz:najpierw stwórzmy puste pliki:
zobacz pliki i nie zawierają one nic:
uruchom magiczne polecenie, używając
xargs
:wynik:
Właśnie udało Ci się zastąpić oba
mypreciousfile.dat
imypreciousfile.dat.ans
. Gdyby w tych plikach znajdowała się jakaś zawartość, zostałaby usunięta.2. Używanie
xargs
: właściwy sposób zfind
Jeśli chcesz nalegać na użycie
xargs
, użyj-0
(nazwy zakończone znakiem null):Zwróć uwagę na dwie rzeczy:
.dat.ans
zakończeniem;"
).Oba problemy można rozwiązać przez inny sposób wywoływania powłoki:
3. Wszystko zrobione wewnątrz
find ... -exec
To ponownie tworzy
.dat.ans
pliki i ulegnie uszkodzeniu, jeśli zawierają nazwy plików"
. Aby to zrobić, użyjbash
i zmień sposób wywoływania:źródło
zsh
jest używany jako powłoka (a SH_WORD_SPLIT nie jest ustawiony), wszystkie nieprzyjemne przypadki specjalne (białe spacje, „w nazwie pliku itp.)) Nie muszą być brane pod uwagę. Trywialnośćfor file in A/*.dat; do ./a.out < $file > ${file%.dat}.ans ; done
działa we wszystkich przypadkach.find
.Spróbuj zrobić coś takiego (składnia może się nieco różnić w zależności od używanej powłoki):
$ for i in $(find A/ -name \*.dat); do ./a.out < ${i} > ${i%.dat}.ans; done
źródło
somefile.dat.dat
i przekierowywać wszystkie dane wyjściowe do jednego pliku.somefile.dat.ans
Rzeczy wyjściowe nie wyglądałyby tak ładnie.-type file
byłoby fajne (nie może< directory
), a to sprawia, że niezwykła nazwa pliku-bajki jest smutna.W przypadku prostych wzorów odpowiednia jest pętla for:
W bardziej skomplikowanych przypadkach, gdy potrzebujesz innego narzędzia do wyświetlenia listy plików (zsh lub bash 4 mają wystarczająco mocne wzorce, których rzadko potrzebujesz znaleźć, ale jeśli chcesz pozostać w powłoce POSIX lub użyć szybkiej powłoki jak dash, będziesz musiał znaleźć cokolwiek nietrywialne), podczas gdy najbardziej odpowiednie jest czytanie:
Będzie to obsługiwać spacje, ponieważ odczyt jest (domyślnie) zorientowany liniowo. Nie będzie obsługiwał znaków nowej linii i nie będzie obsługiwał ukośników odwrotnych, ponieważ domyślnie interpretuje sekwencje specjalne (co w rzeczywistości umożliwia przejście do nowego wiersza, ale find nie może wygenerować tego formatu). Wiele powłok ma
-0
opcję odczytu, więc w tych można obsłużyć wszystkie znaki, ale niestety nie jest to POSIX.źródło
Użyj GNU Parallel:
Dodano bonus: przetwarzanie odbywa się równolegle.
Obejrzyj filmy wprowadzające, aby dowiedzieć się więcej: http://www.youtube.com/watch?v=OpaiGYxkSuQ
źródło
Myślę, że potrzebujesz przynajmniej wywołania powłoki w xargs:
Edycja: Należy zauważyć, że to podejście nie działa, gdy nazwy plików zawierają spacje. Nie działa Nawet jeśli użyjesz find -0 i xargs -0, aby xargs poprawnie zrozumiał spacje, wywołanie powłoki -c na nich zaskoczy. Jednak OP wyraźnie poprosił o rozwiązanie xargs i jest to najlepsze rozwiązanie xargs, jakie wymyśliłem. Jeśli spacje w nazwach plików mogą stanowić problem, użyj find -exec lub pętli powłoki.
źródło
ls
danych wyjściowych jest złym pomysłem .ls
wyświetla rzeczy takie jak spacje bez ucieczki i to jest problem.ls
nie jest dobre. Alexargs
można bezpiecznie używać z find - patrz sugestia nr 2 w mojej odpowiedzi.Nie trzeba tego komplikować. Możesz to zrobić za pomocą
for
pętli:${file%.dat}.ans
nieco usunie.dat
przyrostek nazwy pliku z pliku w$file
i zamiast dodawać.ans
do końca.źródło