Przede wszystkim nie należy używać lsdanych 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 xargsużycia.
1. Prosty sposób: dla pętli
Jeśli chcesz przetworzyć tylko pliki poniżej A/, wystarczy zwykła forpę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 lsz xargsdo 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.dati 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.anszakoń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.anspliki i ulegnie uszkodzeniu, jeśli zawierają nazwy plików ". Aby to zrobić, użyj bashi zmień sposób wywoływania:
find A/ -name "*.dat" -type f -exec bash -c './a.out < "$0" > "${0%dat}ans"' {} \;