Saya ingin menjalankan:
./a.out < x.dat > x.ans
untuk setiap * Dat file dalam direktori A .
Tentu, itu bisa dilakukan dengan skrip bash / python / apa pun, tapi saya suka menulis seksi satu baris. Yang bisa saya capai adalah (masih tanpa stdout):
ls A/*.dat | xargs -I file -a file ./a.out
Tapi -a dalam xargs tidak mengerti ganti-str 'file'.
Terima kasih atas bantuan Anda.
io-redirection
xargs
Nikolay Vyahhi
sumber
sumber
Jawaban:
Pertama-tama, jangan gunakan
ls
output sebagai daftar file . Gunakan ekspansi shell ataufind
. Lihat di bawah ini untuk konsekuensi potensial dari penyalahgunaan ls + xargs dan contohxargs
penggunaan yang tepat .1. Cara sederhana: untuk loop
Jika Anda ingin memproses hanya file-file di bawah
A/
, makafor
loop sederhana harus cukup:2. pre1 Kenapa tidak
ls | xargs
?Berikut ini adalah contoh bagaimana hal-hal buruk bisa berubah jika Anda menggunakan
ls
denganxargs
untuk pekerjaan itu. Pertimbangkan skenario berikut:pertama, mari kita buat beberapa file kosong:
lihat file dan tidak mengandung apa pun:
jalankan perintah ajaib menggunakan
xargs
:hasil:
Jadi, Anda baru saja berhasil menimpa keduanya
mypreciousfile.dat
danmypreciousfile.dat.ans
. Jika ada konten dalam file itu, itu akan dihapus.2. Menggunakan
xargs
: cara yang tepat denganfind
Jika Anda ingin tetap menggunakan
xargs
, gunakan-0
(nama yang dihentikan nol):Perhatikan dua hal:
.dat.ans
akhiran;"
).Kedua masalah dapat diselesaikan dengan cara doa shell yang berbeda:
3. Semua dilakukan di dalam
find ... -exec
Ini, sekali lagi, menghasilkan
.dat.ans
file dan akan pecah jika nama file berisi"
. Untuk melakukannya, gunakanbash
dan ubah cara pemanggilannya:sumber
zsh
digunakan sebagai shell (dan SH_WORD_SPLIT tidak disetel), semua case khusus jahat (spasi putih, "dalam nama file, dll.) Tidak perlu dipertimbangkan. Sepelefor file in A/*.dat; do ./a.out < $file > ${file%.dat}.ans ; done
berfungsi dalam semua kasus.find
.Coba lakukan sesuatu seperti ini (sintaks mungkin sedikit berbeda tergantung pada shell yang Anda gunakan):
$ for i in $(find A/ -name \*.dat); do ./a.out < ${i} > ${i%.dat}.ans; done
sumber
somefile.dat.dat
dan mengarahkan semua output ke satu file.somefile.dat.ans
menampilkan barang-barang akan terlihat tidak begitu baik.-type file
akan menyenangkan (tidak bisa< directory
), dan ini membuat peri-nama-peri-biasa sedih.Untuk pola sederhana, for loop sesuai:
Untuk kasus yang lebih kompleks di mana Anda memerlukan utilitas lain untuk membuat daftar file (zsh atau bash 4 memiliki pola yang cukup kuat yang jarang perlu Anda temukan, tetapi jika Anda ingin tetap berada dalam shell POSIX atau menggunakan shell cepat seperti dash, Anda perlu mencari apa saja non-sepele), saat membaca paling tepat:
Ini akan menangani spasi, karena membaca (secara default) berorientasi garis. Itu tidak akan menangani baris baru dan tidak akan menangani garis miring terbalik, karena secara default ia menafsirkan urutan melarikan diri (yang sebenarnya memungkinkan Anda untuk melewati baris baru, tetapi menemukan tidak dapat menghasilkan format itu). Banyak shell memiliki
-0
opsi untuk membaca sehingga Anda dapat menangani semua karakter, tetapi sayangnya itu bukan POSIX.sumber
Gunakan GNU Parallel:
Bonus tambahan: Anda menyelesaikan pemrosesan secara paralel.
Tonton video intro untuk mempelajari lebih lanjut: http://www.youtube.com/watch?v=OpaiGYxkSuQ
sumber
Saya pikir Anda memerlukan setidaknya doa shell di xargs:
Sunting: Perlu dicatat bahwa pendekatan ini tidak berfungsi ketika nama file mengandung spasi. Tidak bisa bekerja Bahkan jika Anda menggunakan find -0 dan xargs -0 untuk membuat xargs memahami spasi dengan benar, panggilan shell -c akan mengacaukannya. Namun, OP secara eksplisit meminta solusi xargs, dan ini adalah solusi xargs terbaik yang saya dapatkan. Jika spasi putih dalam nama file mungkin menjadi masalah, gunakan find -exec atau shell loop.
sumber
ls
output .ls
mengeluarkan hal-hal seperti spasi tanpa melarikan diri dan itulah masalahnya.ls
tidak baik. Tetapixargs
dapat digunakan dengan aman dengan menemukan - lihat saran No 2 dalam jawaban saya.Tidak perlu menyulitkannya. Anda bisa melakukannya dengan
for
loop:yang
${file%.dat}.ans
sedikit akan menghapus.dat
akhiran nama file dari nama file di$file
dan bukannya menambahkan.ans
sampai akhir.sumber