Przede wszystkim nie należy używać ls
danych wyjściowych jako listy plików . Użyj rozszerzenia powłoki lub find
. Poniżej przedstawiono potencjalne konsekwencje niewłaściwego użycia ls + xargs i przykład prawidłowego xargs
użycia.
1. Prosty sposób: dla pętli
Jeśli chcesz przetworzyć tylko pliki poniżej A/
, wystarczy zwykła for
pętla:
for file in A/*.dat; do ./a.out < "$file" > "${file%.dat}.ans"; done
2. pre1 Dlaczego nie ls | xargs
?
Oto przykład tego, jak złe rzeczy mogą włączyć w przypadku korzystania ls
z xargs
do pracy. Rozważ następujący scenariusz:
najpierw stwórzmy puste pliki:
$ touch A/mypreciousfile.dat\ with\ junk\ at\ the\ end.dat
$ touch A/mypreciousfile.dat
$ touch A/mypreciousfile.dat.ans
zobacz pliki i nie zawierają one nic:
$ ls -1 A/
mypreciousfile.dat
mypreciousfile.dat with junk at the end.dat
mypreciousfile.dat.ans
$ cat A/*
uruchom magiczne polecenie, używając xargs
:
$ ls A/*.dat | xargs -I file sh -c "echo TRICKED > file.ans"
wynik:
$ cat A/mypreciousfile.dat
TRICKED with junk at the end.dat.ans
$ cat A/mypreciousfile.dat.ans
TRICKED
Właśnie udało Ci się zastąpić oba mypreciousfile.dat
i mypreciousfile.dat.ans
. Gdyby w tych plikach znajdowała się jakaś zawartość, zostałaby usunięta.
2. Używanie xargs
: właściwy sposób z find
Jeśli chcesz nalegać na użycie xargs
, użyj -0
(nazwy zakończone znakiem null):
find A/ -name "*.dat" -type f -print0 | xargs -0 -I file sh -c './a.out < "file" > "file.ans"'
Zwróć uwagę na dwie rzeczy:
- w ten sposób będziesz tworzyć pliki z
.dat.ans
zakończeniem;
- to się zepsuje, jeśli jakaś nazwa pliku zawiera znak cudzysłowu (
"
).
Oba problemy można rozwiązać przez inny sposób wywoływania powłoki:
find A/ -name "*.dat" -type f -print0 | xargs -0 -L 1 bash -c './a.out < "$0" > "${0%dat}ans"'
3. Wszystko zrobione wewnątrz find ... -exec
find A/ -name "*.dat" -type f -exec sh -c './a.out < "{}" > "{}.ans"' \;
To ponownie tworzy .dat.ans
pliki i ulegnie uszkodzeniu, jeśli zawierają nazwy plików "
. Aby to zrobić, użyj bash
i zmień sposób wywoływania:
find A/ -name "*.dat" -type f -exec bash -c './a.out < "$0" > "${0%dat}ans"' {} \;