Bisakah seseorang tolong berikan kode untuk melakukan hal berikut: Asumsikan ada direktori file, yang semuanya perlu dijalankan melalui program. Program mengeluarkan hasil ke standar keluar. Saya membutuhkan skrip yang akan masuk ke direktori, menjalankan perintah pada setiap file, dan menyatukan output menjadi satu file output besar.
Misalnya, untuk menjalankan perintah pada 1 file:
$ cmd [option] [filename] > results.out
ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out
ls
untuk mengemudixargs
. Jikacmd
ditulis dengan kompeten, mungkin Anda bisa melakukannyacmd <wildcard>
.Jawaban:
Kode bash berikut akan mengirimkan $ file ke perintah di mana $ file akan mewakili setiap file dalam / dir
Contoh
sumber
/dir/
, maka loop masih berjalan sekali dengan nilai '*' untuk$file
, yang mungkin tidak diinginkan. Untuk menghindari ini, aktifkan nullglob selama durasi loop. Tambahkan baris ini sebelum loopshopt -s nullglob
dan baris ini setelah loopshopt -u nullglob #revert nullglob back to it's normal default state
.done >results.out
(dan mungkin Anda dapat menimpa alih-alih menambahkan, seperti yang saya asumsikan di sini).Bagaimana dengan ini:
-maxdepth 1
Argumen mencegah penemuan turun secara rekursif ke subdirektori mana pun. (Jika Anda ingin direktori bersarang tersebut diproses, Anda dapat mengabaikan ini.)-type -f
menetapkan bahwa hanya file biasa yang akan diproses.-exec cmd option {}
memintanya untuk menjalankancmd
dengan ditentukanoption
untuk setiap file yang ditemukan, dengan nama file diganti{}
\;
menunjukkan akhir dari perintah.cmd
eksekusi individu diarahkan keresults.out
Namun, jika Anda peduli tentang urutan file diproses, Anda mungkin lebih baik menulis satu lingkaran. Saya pikir
find
memproses file dalam urutan inode (meskipun saya bisa salah tentang itu), yang mungkin bukan yang Anda inginkan.sumber
stat
dansort
, yang tentu saja tergantung pada apa yang menyortir kriteria.-exec
opsi? Apakah saya harus membungkusnya dengan tanda kutip tunggal atau sesuatu?find
selalu merupakan opsi terbaik karena Anda dapat memfilter menurut pola nama file dengan opsi-name
dan Anda dapat melakukannya dalam satu perintah.-exec
opsi:find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;
Saya melakukan ini pada pi raspberry saya dari baris perintah dengan menjalankan:
sumber
Jawaban yang diterima / terpilih adalah bagus, tetapi mereka kekurangan beberapa detail yang rumit. Posting ini membahas kasus-kasus tentang bagaimana menangani dengan lebih baik ketika ekspansi shell-path-name (glob) gagal, ketika nama-nama file mengandung baris baru / simbol dasbor dan memindahkan output perintah re-direction keluar dari for-loop saat menulis hasil ke mengajukan.
Ketika menjalankan ekspansi shell glob menggunakan
*
ada kemungkinan ekspansi gagal jika tidak ada file yang ada dalam direktori dan string glob yang tidak diperluas akan diteruskan ke perintah yang akan dijalankan, yang bisa memiliki hasil yang tidak diinginkan. Thebash
shell menyediakan pilihan shell diperpanjang untuk menggunakan ininullglob
. Jadi loop pada dasarnya menjadi sebagai berikut di dalam direktori yang berisi file-file AndaIni memungkinkan Anda keluar dari loop for aman ketika ekspresi
./*
tidak mengembalikan file apa pun (jika direktori kosong)atau dengan cara POSIX compliant (
nullglob
adalahbash
khusus)Ini memungkinkan Anda masuk ke dalam loop ketika ekspresi gagal untuk sekali dan kondisi
[ -f "$file" ]
memeriksa apakah string yang tidak diperluas./*
adalah nama file yang valid di direktori itu, yang tidak akan. Jadi pada kegagalan kondisi ini, menggunakancontinue
kami melanjutkan kembali kefor
loop yang tidak akan berjalan selanjutnya.Perhatikan juga penggunaan
--
sesaat sebelum melewati argumen nama file. Ini diperlukan karena seperti yang disebutkan sebelumnya, nama file shell dapat berisi tanda hubung di mana saja dalam nama file. Beberapa perintah shell menafsirkannya dan memperlakukannya sebagai opsi perintah ketika nama tidak dikutip dengan benar dan mengeksekusi perintah berpikir jika bendera disediakan.Tanda-
--
tanda akhir opsi baris perintah dalam kasus yang berarti, perintah tidak boleh mengurai string di luar titik ini sebagai flag perintah tetapi hanya sebagai nama file.Mengutip nama file dengan benar memecahkan kasus ketika nama tersebut mengandung karakter gumpal atau spasi putih. Tetapi nama file * nix juga dapat berisi baris baru di dalamnya. Jadi kami membatasi nama file dengan satu-satunya karakter yang tidak dapat menjadi bagian dari nama file yang valid - byte nol (
\0
). Karena secarabash
internal menggunakanC
string gaya di mana byte nol digunakan untuk menunjukkan akhir string, itu adalah kandidat yang tepat untuk ini.Jadi menggunakan
printf
opsi shell untuk membatasi file dengan byte NULL ini menggunakan-d
opsiread
perintah, bisa kita lakukan di bawah iniThe
nullglob
danprintf
melilit(..)
yang berarti mereka pada dasarnya dijalankan dalam sub-shell (shell anak), karena untuk menghindarinullglob
pilihan untuk merenungkan shell orang tua, setelah keluar perintah. The-d ''
pilihan untukread
perintah tidak POSIX compliant, sehingga membutuhkanbash
shell untuk ini harus dilakukan. Menggunakanfind
perintah ini dapat dilakukan sebagaiUntuk
find
implementasi yang tidak mendukung-print0
(selain implementasi GNU dan FreeBSD), ini dapat ditiru dengan menggunakanprintf
Perbaikan penting lainnya adalah memindahkan re-direction dari for-loop untuk mengurangi jumlah file I / O yang tinggi. Ketika digunakan di dalam loop, shell harus menjalankan system-calls dua kali untuk setiap iterasi for-loop, sekali untuk membuka dan sekali untuk menutup deskriptor file yang terkait dengan file. Ini akan menjadi leher botol pada kinerja Anda untuk menjalankan iterasi besar. Saran yang disarankan adalah memindahkannya di luar loop.
Memperluas kode di atas dengan perbaikan ini, bisa Anda lakukan
yang pada dasarnya akan meletakkan isi perintah Anda untuk setiap iterasi input file Anda ke stdout dan ketika loop berakhir, buka file target sekali untuk menulis isi stdout dan simpan. Setara
find
versi yang sama akansumber
Salah satu cara cepat dan kotor yang terkadang menyelesaikan pekerjaan adalah:
Misalnya untuk menemukan jumlah baris di semua file di direktori saat ini, Anda dapat melakukan:
sumber
~/.local/share/steam
. Berlayar. Ini menghapus semua yang ada di sistem yang dimiliki oleh pengguna." laporan bug.Saya perlu menyalin semua file .md dari satu direktori ke direktori lain, jadi inilah yang saya lakukan.
for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done
Yang cukup sulit dibaca, jadi mari kita jabarkan.
cd pertama ke direktori dengan file Anda,
for i in **/*.md;
untuk setiap file dalam pola Andamkdir -p ../docs/"$i"
buat direktori itu di folder dokumen di luar folder yang berisi file Anda. Yang membuat folder ekstra dengan nama yang sama dengan file itu.rm -r ../docs/"$i"
hapus folder tambahan yang dibuat sebagai akibat darimkdir -p
cp "$i" "../docs/$i"
Salin file yang sebenarnyaecho "$i -> ../docs/$i"
Echo apa yang kamu lakukan; done
Hidup bahagia selamanyasumber
**
dapat bekerja,globstar
opsi shell harus diatur:shopt -s globstar
Kamu bisa memakai
xarg
ls | xargs -L 1 -d '\n' your-desired-command
-L 1
menyebabkan lulus 1 item sekaligus-d '\n'
membuat outputls
dibagi berdasarkan baris baru.sumber
Berdasarkan pendekatan @ Jim Lewis:
Berikut ini adalah solusi cepat menggunakan
find
dan juga menyortir file berdasarkan tanggal modifikasinya:Untuk penyortiran, lihat:
http://www.commandlinefu.com/commands/view/5720/find-files-and-list-them-sorted-by-modification-time
sumber
-print0
untukfind
dan-0
untukxargs
yang menggunakan karakter null bukan spasi (termasuk baris baru).-print0
adalah sesuatu yang membantu, tetapi seluruh pipa perlu menggunakan sesuatu seperti ini, dansort
bukansaya pikir solusi sederhana adalah:
sumber
Maxdepth
Saya menemukan ini bekerja dengan baik dengan jawaban Jim Lewis tambahkan sedikit seperti ini:
Sortir Pesanan
Jika Anda ingin mengeksekusi dalam urutan, modifikasi seperti ini:
Sebagai contoh, ini akan dijalankan dengan urutan sebagai berikut:
Kedalaman tidak terbatas
Jika Anda ingin mengeksekusi di kedalaman yang tidak terbatas dengan kondisi tertentu, Anda dapat menggunakan ini:
kemudian letakkan di atas setiap file di direktori anak seperti ini:
dan di suatu tempat di badan file induk:
sumber