Banyak utilitas baris perintah dapat mengambil inputnya baik dari pipa atau sebagai argumen nama file. Untuk skrip shell panjang, saya menemukan memulai rantai dengan cat
membuatnya lebih mudah dibaca, terutama jika perintah pertama akan membutuhkan argumen multi-line.
Membandingkan
sed s/bla/blaha/ data \
| grep blah \
| grep -n babla
dan
cat data \
| sed s/bla/blaha/ \
| grep blah \
| grep -n babla
Apakah metode yang terakhir kurang efisien? Jika demikian, apakah perbedaannya cukup untuk dipedulikan jika skrip dijalankan, katakanlah, satu detik sekali? Perbedaan dalam keterbacaan tidak besar.
shell-script
performance
pipe
cat
tepang
sumber
sumber
cat
. Namun saya pikir pertanyaan yang lebih besar di sini adalah pembacaan kode yang sering merupakan prioritas dibandingkan kinerja. Ketika lebih cepat sebenarnya bisa ditulis lebih cantik , mengapa tidak? Menunjukkan masalah dengancat
biasanya menyebabkan pengguna memiliki pemahaman yang lebih baik tentang saluran pipa dan proses secara umum. Ini sepadan dengan usaha sehingga mereka menulis kode yang dapat dipahami di waktu berikutnya.cat
; Poin Caleb tentang menggunakan fungsi dan pengalihan menyelesaikan juga.)Jawaban:
Jawaban "pasti" tentu saja diajukan kepada Anda oleh The Use of
cat
Award yang Tidak Berguna .Instantiating cat hanya agar kode Anda membaca berbeda membuat hanya satu proses lagi dan satu set input / output stream yang tidak diperlukan. Biasanya penangguhan nyata dalam skrip Anda akan menjadi loop yang tidak efisien dan pemrosesan aktual. Pada kebanyakan sistem modern, satu tambahan
cat
tidak akan mematikan kinerja Anda, tetapihampirselalu ada cara lain untuk menulis kode Anda.Sebagian besar program, seperti yang Anda perhatikan, dapat menerima argumen untuk file input. Namun, selalu ada builtin shell
<
yang dapat digunakan di mana pun aliran STDIN diharapkan yang akan menyelamatkan Anda satu proses dengan melakukan pekerjaan dalam proses shell yang sudah berjalan.Anda bahkan dapat berkreasi dengan DIMANA Anda menulisnya. Biasanya itu akan ditempatkan di akhir perintah sebelum Anda menentukan pengalihan atau pipa keluaran seperti ini:
Tetapi tidak harus seperti itu. Bahkan bisa didahulukan. Misalnya kode contoh Anda dapat ditulis seperti ini:
Jika keterbacaan skrip menjadi perhatian Anda dan kode Anda cukup berantakan sehingga menambahkan baris untuk
cat
diharapkan untuk membuatnya lebih mudah diikuti, ada cara lain untuk membersihkan kode Anda. Salah satu yang saya gunakan banyak yang membantu membuat skrip mudah untuk mencari tahu nanti adalah memecah pipa menjadi set logis dan menyimpannya dalam fungsi. Kode skrip kemudian menjadi sangat alami, dan salah satu bagian dari pipline lebih mudah di-debug.Anda kemudian dapat melanjutkan
fix_blahs < data | fix_frogs | reorder | format_for_sql
. Sebuah pipleline yang bertuliskan seperti itu sangat mudah diikuti, dan masing-masing komponen dapat di-debug dengan mudah di fungsinya masing-masing.sumber
<file
bisa datang sebelum perintah. Ini menyelesaikan semua masalah saya!<file
dapat datang ke mana saja di baris perintah:<file grep needle
ataugrep <file needle
ataugrep needle <file
. Pengecualian adalah perintah kompleks seperti loop dan pengelompokan; di sana pengalihan harus dilakukan setelah penutupandone
/}
/)
/ etc. @ Caleb Ini berlaku untuk semua cangkang Bourne / POSIX. Dan saya tidak setuju bahwa itu jelek.$(cat /some/file)
dengan$(< /some/file)
, yang melakukan hal yang sama tetapi menghindari proses pemijahan.$(< /some/file)
portabilitasnya terbatas. Itu berfungsi di bash, tetapi tidak BusyBox ash, misalnya, atau FreeBSD sh. Mungkin juga tidak bekerja dengan cepat, karena ketiga kerang terakhir itu adalah sepupu dekat.Berikut ringkasan dari beberapa kekurangan:
lebih
$file
atas. Dalam kasuscat
, itu selalu menjadi masalah kecuali untukzsh
; dalam kasus pengalihan, itu hanya masalah untukbash
atauksh88
dan, untuk beberapa shell lain hanya ketika interaktif (bukan dalam skrip).cmd
builtin, itu bahkan 2 proses di beberapa shell sepertibash
.cat
builtin, itu juga perintah tambahan dieksekusi (dan tentu saja dimuat, dan diinisialisasi (dan perpustakaan itu terhubung juga)).cat
dancmd
memproses secara bergantian dan terus-menerus mengisi dan mengosongkan buffer pipa. Bahkan jikacmd
tidak1GB
besarread()
panggilan sistem pada suatu waktu, kontrol harus bolak-balik antaracat
dancmd
karena pipa tidak bisa menahan lebih dari beberapa kilobyte data pada suatu waktu.cmd
(sepertiwc -c
) dapat melakukan beberapa optimasi ketika stdin mereka adalah file biasa yang tidak dapat mereka lakukancat | cmd
karena stdin mereka hanyalah sebuah pipa saja. Dengancat
dan sebuah pipa, itu juga berarti mereka tidak dapatseek()
berada di dalam file. Untuk perintah sepertitac
atautail
, itu membuat perbedaan besar dalam kinerja karena itu berarti bahwacat
mereka perlu menyimpan seluruh input dalam memori.cat $file
, dan bahkan versi yang lebih benarcat -- "$file"
tidak akan berfungsi dengan baik untuk beberapa nama file tertentu seperti-
(--help
atau apa pun yang dimulai dengan-
jika Anda lupa--
). Jika seseorang bersikeras menggunakancat
, ia mungkin harus menggunakancat < "$file" | cmd
sebagai gantinya untuk keandalan.$file
tidak dapat dibuka untuk dibaca (akses ditolak, tidak ada ...),< "$file" cmd
akan melaporkan pesan kesalahan yang konsisten (oleh shell) dan tidak berjalancmd
, sementaracat $file | cmd
masih akan berjalancmd
tetapi dengan stdin yang terlihat seperti itu adalah file kosong. Itu juga berarti bahwa dalam hal-hal seperti< file cmd > file2
,file2
tidak musnah jikafile
tidak bisa dibuka.sumber
truncate -s10G a; time wc -c < a; time cat a | wc -c; time cat a | cat | wc -c
. Ada banyak parameter yang masuk ke dalam gambar. Penalti kinerja dapat berubah dari 0 hingga 100%. Bagaimanapun, saya tidak berpikir hukumannya bisa negatif.wc -c
adalah kasus yang cukup unik, karena memiliki jalan pintas. Jika Anda melakukannyawc -w
maka itu dapat dibandingkan dengangrep
dalam contoh saya (yaitu sangat sedikit pemrosesan - yang merupakan situasi di mana '<' dapat membuat perbedaan).wc -w
pada file jarang 1GB di lokal C di linux 4.9 amd64) maka saya menemukan pendekatan kucing membutuhkan 23% lebih banyak waktu ketika pada sistem multicore dan 5% ketika mengikat mereka ke satu inti. Menampilkan overhead tambahan yang dikeluarkan dengan memiliki data yang diakses oleh lebih dari satu inti. Anda mungkin akan mendapatkan hasil yang berbeda jika Anda mengubah ukuran pipa, menggunakan data yang berbeda, melibatkan I / O nyata menggunakan implementasi kucing yang menggunakan splice () ... Semua mengonfirmasi bahwa ada banyak parameter yang didapat dalam gambar dan dalam hal apa puncat
tidak akan membantu.wc -w
itu perbedaan sekitar 2% ... perbedaan 15% jika itu menjadi grep sederhana lurus. Kemudian, anehnya, jika itu ada di berbagi file NFS itu sebenarnya 20% lebih cepat untuk membacanya jika disalurkan daricat
( gist.github.com/rdp/7162414833becbee5919cda855f1cb86 ) Aneh ...Memasang
<file
ujung pipa kurang bisa dibaca daripada memilikicat file
di awal. Bahasa Inggris Alami berbunyi dari kiri ke kanan.Menempatkan
<file
awal pipa juga kurang dapat dibaca daripada kucing, saya akan mengatakan. Sebuah kata lebih mudah dibaca daripada simbol, terutama simbol yang sepertinya menunjuk ke arah yang salah.Menggunakan
cat
mempertahankancommand | command | command
format.sumber
<
sekali membuat kode kurang mudah dibaca, karena merusak konsistensi sintaksis dari sebuah multipipeline.<
menyukai ini:alias load='<'
dan kemudian gunakan misalnyaload file | sed ...
. Alias dapat digunakan dalam skrip setelah dijalankanshopt -s expand_aliases
.Satu hal yang tampaknya tidak dijawab langsung oleh jawaban lain di sini adalah bahwa menggunakan
cat
seperti ini bukan "tidak berguna" dalam arti bahwa "proses kucing asing muncul yang tidak bekerja"; tidak ada gunanya dalam arti "proses kucing muncul yang hanya bekerja tidak perlu".Dalam hal ini keduanya:
shell memulai proses sed yang membaca dari somefile atau stdin (masing-masing) dan kemudian melakukan beberapa pemrosesan - ia membaca sampai menyentuh baris baru, menggantikan 'foo' pertama (jika ada) pada baris itu dengan 'bar', kemudian mencetak baris ke stdout dan loop.
Dalam kasus:
Shell memunculkan proses kucing dan proses sed, dan kabel stdout kucing ke stdin sed. Proses cat membaca beberapa kilo atau mungkin potongan mega-byte dari file, kemudian menuliskannya ke stdout, di mana perintah sed mengambil dari sana seperti pada contoh kedua di atas. Sementara sed sedang memproses potongan itu, kucing membaca potongan lain dan menulisnya di stdout untuk sed untuk mengerjakan selanjutnya.
Dengan kata lain, pekerjaan tambahan yang diperlukan dengan menambahkan
cat
perintah bukan hanya pekerjaan ekstra untuk menghasilkancat
proses tambahan , tetapi juga pekerjaan ekstra membaca dan menulis byte file dua kali alih-alih sekali. Sekarang, secara praktis berbicara dan pada sistem modern, itu tidak membuat perbedaan besar - itu mungkin membuat sistem Anda melakukan beberapa mikrodetik dari pekerjaan yang tidak perlu. Tetapi jika itu untuk skrip yang Anda rencanakan untuk didistribusikan, berpotensi untuk orang yang menggunakannya pada mesin yang sudah kurang bertenaga, beberapa mikrodetik dapat menambahkan lebih banyak iterasi.sumber
cat
.cat
dibagi dengan ms tanpacat
dalam persen (mis 264 ms / 216 ms = 1.22 = 122% = 22% lebih lambat dengancat
)