Saya tahu grep
perintah dan saya belajar tentang fungsi xargs
, jadi saya membaca halaman ini yang memberikan beberapa contoh tentang cara menggunakan xargs
perintah.
Saya bingung dengan contoh terakhir, contoh 10. Ia mengatakan "Perintah xargs mengeksekusi perintah grep untuk menemukan semua file (di antara file yang disediakan oleh perintah find) yang berisi string 'stdlib.h'"
$ find . -name '*.c' | xargs grep 'stdlib.h'
./tgsthreads.c:#include
./valgrind.c:#include
./direntry.c:#include
./xvirus.c:#include
./temp.c:#include
...
...
...
Namun, apa bedanya hanya menggunakan
$ find . -name '*.c' | grep 'stdlib.h'
?
Jelas, saya masih berjuang dengan apa yang sebenarnya dilakukan xargs, jadi bantuan apa pun dihargai!
command-line
grep
xargs
Alpha Omega
sumber
sumber
Jawaban:
Ini mem-pipe output (stdout) * dari
find
ke (stdin of) *grep 'stdlib.h'
sebagai teks (mis. Nama file diperlakukan sebagai teks).grep
melakukan hal yang biasa dan menemukan baris yang cocok dalam teks ini (nama file apa pun yang mengandung pola). Isi file tidak pernah dibaca.Ini membangun sebuah perintah di
grep 'stdlib.h'
mana setiap hasil darifind
adalah argumen - jadi ini akan mencari kecocokan di dalam setiap file yang ditemukan olehfind
(xargs
dapat dianggap sebagai mengubah stdin menjadi argumen ke perintah yang diberikan) *Gunakan
-type f
di perintah find Anda, atau Anda akan mendapatkan kesalahan darigrep
direktori yang cocok. Juga, jika nama file memiliki spasi,xargs
akan gagal total, jadi gunakan pemisah nol dengan menambahkan-print0
danxargs -0
untuk hasil yang lebih andal:* menambahkan poin penjelasan tambahan ini seperti yang disarankan dalam komentar oleh @cat
sumber
|
pipa stdout ke grep ini stdin yang tidak sama dengan argumen grep dan memberikan hasil yang membingungkan.find -name '*.c' -exec grep stdlib.h {} +
. Saya sebenarnya tidak pernah menggunakan xargs. Juga terkejut bahwa tidak ada yang menyebutkan bahwa xargs memiliki tujuan yang mirip dengangrep $(find)
perintah substitusi, jadi saya menulis jawaban saya sendiri. Menjelaskan xargs sebagai substitusi perintah dengan batasan dan masalah yang lebih sedikit tampak wajar.find -delete
untuk kasus khusus itu? Atau untuk perintah selainrm
, jika Anda memiliki GNU find, maka-exec some_command {} +
kelompokkan ke dalam batch seperti xargs, alih-alih\;
perilaku menjalankan perintah secara terpisah untuk masing-masing.find
menjalankan perintah pada setiap file jika dan hanya jika menggunakan-exec command \;
Keduanyaxargs
dan-exec command \+
akan memanggil perintah dengan jumlah argumen maksimum yang diizinkan oleh sistem. Dengan kata lain, mereka setaraxargs mengambil input standar dan mengubahnya menjadi baris perintah args.
find . -name '*.c' | xargs grep 'stdlib.h'
sangat mirip denganDan akan memberikan hasil yang sama selama daftar nama file tidak terlalu panjang untuk satu baris perintah. (Linux mendukung megabyte teks pada satu baris perintah, jadi biasanya Anda tidak perlu xargs.)
Tetapi keduanya menyebalkan, karena mereka rusak jika nama file Anda mengandung spasi . Sebaliknya,
find -print0 | xargs -0
bekerja, tetapi begitu jugaItu tidak pernah menyalurkan nama file di mana saja:
find
batch mereka menjadi baris perintah besar dan berjalangrep
secara langsung.\;
bukannya+
menjalankan grep secara terpisah untuk setiap file, yang jauh lebih lambat. Jangan lakukan itu. Tetapi+
ini adalah ekstensi GNU, jadi Anda harusxargs
melakukan ini secara efisien jika Anda tidak dapat menganggap GNU find.Jika Anda keluar
xargs
,find | grep
apakah polanya cocok dengan daftar nama file yangfind
dicetak.Jadi pada titik itu, sebaiknya Anda lakukan saja
find -name stdlib.h
. Tentu saja, dengan-name '*.c' -name stdlib.h
, Anda tidak akan mendapatkan hasil apa pun karena pola-pola itu tidak bisa cocok, dan perilaku default find adalah untuk DAN aturan bersama.Gantikan
less
pada titik mana saja dalam proses untuk melihat output apa saja yang dihasilkan oleh bagian pipa.Bacaan lebih lanjut: http://mywiki.wooledge.org/BashFAQ memiliki beberapa hal hebat.
sumber
-d
mengatur pemisah, sehingga Anda dapat menggunakan-d'\n'
untuk menangani daftar yang dipisahkan oleh baris baru, yang mungkin berguna jika Anda menangani daftar nama file dalam file, dll. (Selama nama file tidak memiliki baris baru di dalamnya, yaitu.)myfunc(){ local IFS=$'\n'; fgrep
stdlib.h` $ (find); }
juga berfungsi dengan efek yang sama. Atau sebagai one-liner, sebuah(IFS=...; cmd...)
subkulit juga berfungsi untuk memuat perubahan ke IFS tanpa harus menyimpan / mengembalikannya.command $( find )
jenis barang. Nama file bermasalah dengan spasi dan karakter khusus dapat merusak jenis hal ini. Paling tidak dua kali lipat kutipan substitusi perintah.IFS
jadi itu setara dengan menggunakanxargs '-d\n'
. Ekspansi global dan pemrosesan metacharacter shell terjadi sebelum efek substitusi perintah, jadi saya pikir itu aman bahkan dengan nama file yang mengandung$()
atau>
. Setuju bahwa menggunakan pemisahan kata pada substitusi perintah bukanlah praktik yang baik kecuali untuk penggunaan interaktif satu kali di mana Anda mengetahui sesuatu tentang nama file. Tapicommand "$(find)"
ini hanya berguna jika Anda mengharapkannya menghasilkan tepat 1 nama file ...Secara umum,
xargs
digunakan untuk kasus-kasus di mana Anda akan mem-pipe (dengan simbol|
) sesuatu dari satu perintah ke yang lain (Command1 | Command2
), tetapi output dari perintah pertama tidak diterima dengan benar sebagai input untuk perintah kedua.Ini biasanya terjadi ketika perintah kedua tidak menangani input data melalui Standard In (stdin) dengan benar (misalnya: Beberapa baris sebagai input, cara pengaturan baris, karakter yang digunakan sebagai input, beberapa parameter sebagai input, tipe data yang diterima sebagai masukan, dll.). Untuk memberi Anda contoh cepat, uji berikut ini:
Contoh 1:
ls | echo
- Ini tidak akan melakukan apa-apa karenaecho
tidak tahu bagaimana menangani input yang diterimanya. Sekarang dalam kasus ini jika kita menggunakannyaxargs
akan memproses input dengan cara yang dapat ditangani dengan benar olehecho
(misalnya: Sebagai satu baris informasi)ls | xargs echo
- Ini akan menampilkan semua informasi darils
dalam satu barisContoh 2:
Katakanlah saya memiliki beberapa file goLang di dalam folder bernama go. Saya akan mencari mereka dengan sesuatu seperti ini:
find go -name *.go -type f | echo
- Tetapi jika simbol pipa ada danecho
pada akhirnya, itu tidak akan berhasil.find go -name *.go -type f | xargs echo
- Ini akan berhasil berkatxargs
tetapi jika saya ingin setiap tanggapan darifind
perintah dalam satu baris, saya akan melakukan yang berikut:find go -name *.go -type f | xargs -0 echo
- Dalam hal ini, output yang sama darifind
akan ditunjukkan olehecho
.Perintah seperti
cp, echo, rm, less
dan lainnya yang membutuhkan cara yang lebih baik untuk menangani input mendapatkan manfaat saat digunakan bersamaxargs
.sumber
xargs
digunakan untuk menghasilkan argumen baris perintah secara otomatis (biasanya) pada daftar file.Jadi mempertimbangkan beberapa alternatif untuk menggunakan
xargs
perintah followoing :Ada beberapa alasan untuk menggunakannya alih-alih opsi lain yang awalnya tidak disebutkan dalam jawaban lain:
find . -name '*.c' -exec grep 'stdlib.h' {}\;
akan menghasilkan satugrep
proses untuk setiap file — ini umumnya dianggap praktik yang buruk, dan dapat memberi beban besar pada sistem jika ada banyak file yang ditemukan.grep 'stdlib.h' $(find . -name '*.c')
perintah kemungkinan akan gagal, karena output dari$(...)
operasi akan melebihi panjang baris perintah maksimum dari shellSeperti disebutkan dalam jawaban lain, alasan untuk menggunakan
-print0
argumenfind
dalam skenario ini dan-0
argumen untuk xargs, adalah agar nama file dengan karakter tertentu (misalnya kutipan, spasi atau bahkan baris baru) masih ditangani dengan benar.sumber