Mengapa shell tidak secara otomatis memperbaiki "penggunaan kucing yang tidak berguna"? [Tutup]

28

Banyak orang menggunakan oneliners dan skrip yang berisi kode di sepanjang baris

cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Yang pertama catsering disebut "penggunaan kucing yang tidak berguna" karena secara teknis ia memerlukan memulai proses baru (sering /usr/bin/cat) di mana ini dapat dihindari jika perintah telah

< "$MYFILE" command1 | command2 > "$OUTPUT"

karena itu shell hanya perlu memulai command1dan cukup arahkan stdinke file yang diberikan.

Mengapa shell tidak melakukan konversi ini secara otomatis? Saya merasa bahwa sintaks "penggunaan kucing yang tidak berguna" lebih mudah dibaca dan shell harus memiliki informasi yang cukup untuk menyingkirkan kucing yang tidak berguna secara otomatis. Ini catdidefinisikan dalam standar POSIX sehingga shell harus diizinkan untuk mengimplementasikannya secara internal daripada menggunakan biner di jalur. Shell bahkan bisa memuat implementasi hanya untuk satu versi argumen dan mundur ke biner di jalur.

Mikko Rantalainen
sumber
22
Perintah-perintah itu sebenarnya tidak setara, karena dalam satu kasus stdin adalah file, dan di lain itu adalah pipa, jadi itu bukan konversi yang sepenuhnya aman. Anda bisa membuat sistem yang melakukannya.
Michael Homer
14
Anda tidak dapat membayangkan use case tidak berarti bahwa aplikasi tidak diizinkan untuk mengandalkan perilaku yang ditentukan secara sia-sia. Mendapatkan kesalahan dari lseekmasih didefinisikan perilaku dan dapat menyebabkan hasil yang berbeda, perilaku memblokir yang berbeda dapat bermakna secara semantik, dll. Ini akan diizinkan untuk melakukan perubahan jika Anda tahu apa perintah lain dan tahu mereka tidak peduli, atau jika Anda tidak peduli tentang kompatibilitas pada tingkat itu, tetapi manfaatnya cukup kecil. Saya membayangkan kurangnya manfaat mendorong situasi lebih dari biaya kesesuaian.
Michael Homer
3
Shell benar-benar diizinkan untuk mengimplementasikannya catsendiri, atau utilitas lainnya. Ini juga memungkinkan untuk mengetahui bagaimana utilitas lain yang termasuk ke dalam sistem kerja (misalnya dapat mengetahui bagaimana eksternal grepimplementasi yang datang dengan sistem berperilaku). Ini benar-benar layak untuk dilakukan, jadi sepenuhnya adil untuk bertanya-tanya mengapa mereka tidak melakukannya.
Michael Homer
6
@MichaelHomer misalnya dapat mengetahui bagaimana implementasi grep eksternal yang datang dengan sistem berperilaku Jadi shell sekarang memiliki ketergantungan pada perilaku grep. Dan sed. Dan awk. Dan du. Dan berapa ratus jika tidak ribuan utilitas lainnya?
Andrew Henle
19
Akan sangat keren dari shell saya untuk mengedit perintah saya untuk saya.
Azor Ahai

Jawaban:

25

2 perintah tidak setara: pertimbangkan penanganan kesalahan:

cat <file that doesn't exist> | less akan menghasilkan aliran kosong yang akan diteruskan ke program yang disalurkan ... dengan demikian Anda berakhir dengan tampilan yang tidak menunjukkan apa-apa.

< <file that doesn't exist> less akan gagal membuka bilah, dan kemudian tidak membuka sama sekali.

Mencoba mengubah yang pertama ke yang kedua dapat mematahkan sejumlah skrip yang berharap untuk menjalankan program dengan input yang berpotensi kosong.

UKMonkey
sumber
1
Saya akan menandai respons Anda sebagai diterima karena saya pikir ini adalah perbedaan paling penting antara kedua sintaksis. Varian dengan catakan selalu menjalankan perintah kedua dalam pipeline sedangkan varian dengan pengalihan input saja tidak akan menjalankan perintah sama sekali jika file input tidak ada.
Mikko Rantalainen
Namun, perhatikan bahwa <"missing-file" grep foo | echo 2tidak akan mengeksekusi greptetapi akan mengeksekusi echo.
Mikko Rantalainen
51

"Penggunaan yang tidak berguna cat" lebih tentang bagaimana Anda menulis kode Anda daripada tentang apa yang sebenarnya berjalan ketika Anda menjalankan skrip. Ini semacam desain anti-pola , cara melakukan sesuatu yang mungkin bisa dilakukan dengan cara yang lebih efisien. Ini adalah kegagalan dalam memahami cara terbaik menggabungkan alat yang diberikan untuk membuat alat baru. Saya berpendapat bahwa merangkai beberapa seddan / atau awkperintah bersama dalam satu pipeline juga kadang-kadang bisa dikatakan sebagai gejala dari pola anti-sama.

Memperbaiki contoh "penggunaan yang tidak berguna cat" dalam skrip adalah masalah utama memperbaiki kode sumber skrip secara manual. Alat seperti ShellCheck dapat membantu dengan menunjukkan kasus-kasus nyata:

$ cat script.sh
#!/bin/sh
cat file | cat
$ shellcheck script.sh

In script.sh line 2:
cat file | cat
    ^-- SC2002: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.

Mendapatkan shell untuk melakukan ini secara otomatis akan sulit karena sifat skrip shell. Cara skrip dijalankan tergantung pada lingkungan yang diwarisi dari proses induknya, dan pada implementasi spesifik dari perintah eksternal yang tersedia.

Shell belum tentu tahu apa catitu. Ini bisa berpotensi perintah apa saja dari mana saja di Anda $PATH, atau fungsi.

Jika itu adalah perintah bawaan (yang mungkin ada di beberapa shell), ia akan memiliki kemampuan untuk mengatur ulang pipa karena akan mengetahui semantik dari catperintah bawaannya. Sebelum melakukan itu, itu juga harus membuat asumsi tentang perintah berikutnya dalam pipa, setelah yang asli cat.

Perhatikan bahwa membaca dari input standar berperilaku sedikit berbeda ketika terhubung ke pipa dan ketika terhubung ke file. Sebuah pipa tidak dapat dicari, jadi tergantung pada apa yang dilakukan perintah berikutnya dalam pipa, itu mungkin atau mungkin tidak berperilaku berbeda jika pipa itu ditata ulang (itu mungkin mendeteksi apakah input dapat dicari dan memutuskan untuk melakukan hal-hal yang berbeda jika itu atau jika tidak, dalam hal apapun itu kemudian akan berperilaku berbeda).

Pertanyaan ini mirip (dalam arti yang sangat umum) dengan " Apakah ada kompiler yang mencoba untuk memperbaiki kesalahan sintaks sendiri? " (Di situs Rekayasa Perangkat Lunak StackExchange), meskipun pertanyaan itu jelas tentang kesalahan sintaks, bukan pola desain yang tidak berguna . Gagasan tentang mengubah kode secara otomatis berdasarkan niat sebagian besar sama.

Kusalananda
sumber
Sangat sesuai bagi shell untuk mengetahui apa catitu, dan perintah-perintah lain dalam pipeline, (aturan as-if) dan berperilaku sesuai, mereka tidak di sini karena tidak ada gunanya dan terlalu sulit.
Michael Homer
4
@MichaelHomer Ya. Tapi itu juga diizinkan untuk membebani perintah standar dengan fungsi dengan nama yang sama.
Kusalananda
2
@ PhilipCouling Ini benar-benar sesuai selama itu diketahui bahwa tidak ada perintah pipa yang peduli. Shell secara khusus diizinkan untuk mengganti utilitas dengan fungsi builtin atau shell dan yang tidak memiliki batasan lingkungan eksekusi, sehingga selama hasil eksternal tidak dapat dibedakan, maka diizinkan. Untuk kasus Anda, cat /dev/ttyadalah yang menarik yang akan berbeda dengannya <.
Michael Homer
1
@MichaelHomer sehingga selama hasil eksternal tidak dapat dibedakan itu diizinkan Itu berarti perilaku seluruh rangkaian utilitas yang dioptimalkan sedemikian rupa tidak akan pernah bisa berubah . Itu pasti neraka ketergantungan utama.
Andrew Henle
3
@MichaelHomer Seperti komentar lain katakan, tentu saja sangat tepat bagi shell untuk mengetahui bahwa dengan input OP, tidak mungkin untuk mengetahui apa yang catsebenarnya dilakukan perintah tanpa menjalankannya . Untuk semua yang Anda (dan shell) tahu, OP memiliki perintah catdi jalurnya yang merupakan simulasi kucing interaktif, "myfile" hanyalah status permainan yang disimpan, dan command1dan command2sedang memproses beberapa statistik tentang sesi bermain saat ini ...
alephzero
34

Karena itu tidak sia-sia.

Dalam kasus cat file | cmd, fd 0(stdin) cmdakan berupa pipa, dan dalam kasus cmd <fileitu mungkin berupa file, perangkat, dll.

Sebuah pipa memiliki semantik yang berbeda dari file biasa, dan semantiknya bukan bagian dari file biasa:

  • file biasa tidak dapat select(2)diedit atau poll(2)diedit dengan cara yang bermakna; a select(2)di atasnya akan selalu kembali "siap". Antarmuka tingkat lanjut seperti epoll(2)di Linux tidak akan berfungsi dengan file biasa.

  • di Linux ada panggilan sistem ( splice(2), vmsplice(2), tee(2)) yang hanya bekerja pada pipa [1]

Karena catbegitu banyak digunakan, itu dapat diimplementasikan sebagai shell built-in yang akan menghindari proses tambahan, tetapi begitu Anda mulai di jalur itu, hal yang sama dapat dilakukan dengan sebagian besar perintah - mengubah shell menjadi lebih lambat & clunkier perlatau python. mungkin lebih baik menulis bahasa skrip lain dengan sintaksis seperti pipa yang mudah digunakan untuk kelanjutan ;-)

[1] Jika Anda ingin contoh sederhana tidak dibuat untuk kesempatan itu, Anda dapat melihat saya "biner exec dari stdin" git inti dengan beberapa penjelasan dalam komentar di sini . Melaksanakan catdi dalamnya untuk membuatnya bekerja tanpa UUoC akan membuatnya 2 atau 3 kali lebih besar.

mosvy
sumber
2
Bahkan, ksh93 tidak mengimplementasikan beberapa perintah eksternal seperti catinternal.
jrw32982 mendukung Monica
3
cat /dev/urandom | cpu_bound_programmenjalankan read()pemanggilan sistem dalam proses terpisah. Di Linux misalnya, pekerjaan CPU yang sebenarnya menghasilkan lebih banyak angka acak (ketika pool kosong) dilakukan dalam system call itu, jadi menggunakan proses yang terpisah memungkinkan Anda memanfaatkan inti CPU yang terpisah untuk menghasilkan data acak sebagai input. misal dalam Apa cara tercepat untuk menghasilkan file teks 1 GB yang berisi angka acak?
Peter Cordes
4
Lebih penting untuk kebanyakan kasus, itu berarti lseektidak akan berhasil. cat foo.mp4 | mpv -akan berfungsi, tetapi Anda tidak dapat mencari mundur lebih jauh dari buffer cache mpv atau mplayer. Tetapi dengan input yang dialihkan dari suatu file, Anda dapat melakukannya. cat | mpv -adalah salah satu cara untuk memeriksa apakah MP4 memiliki moovatomnya di awal file, sehingga dapat diputar tanpa mencari ke belakang dan belakang (yaitu jika itu cocok untuk streaming). Sangat mudah untuk membayangkan kasus-kasus lain di mana Anda ingin menguji suatu program untuk file yang tidak dapat dicari dengan menjalankannya /dev/stdindengan catvs. redirect.
Peter Cordes
Ini bahkan lebih benar ketika menggunakan xargs cat | somecmd. Jika jalur file melampaui batas buffer perintah, xargsdapat berjalan catbeberapa kali menghasilkan aliran berkelanjutan, sementara menggunakan xargs somecmdsecara langsung sering gagal karena somecmdtidak dapat dijalankan dalam banyak untuk mencapai hasil yang mulus.
tasket
17

Karena mendeteksi kucing yang tidak berguna sangat sulit.

Saya memiliki skrip shell tempat saya menulis

cat | (somecommand <<!
...
/proc/self/fd/3
...
!) 0<&3

Script shell gagal dalam produksi jika catdihapus karena dipanggil via su -c 'script.sh' someuser. Yang tampaknya berlebihan catmenyebabkan pemilik input standar untuk mengubah ke pengguna skrip sedang dijalankan sehingga membuka kembali melalui /procbekerja.

Joshua
sumber
Kasing ini akan sangat mudah karena jelas tidak mengikuti model sederhana catdiikuti oleh tepat satu parameter sehingga shell harus menggunakan catexecutable nyata bukan pintas yang dioptimalkan. Poin bagus tentang kredensial yang mungkin berbeda atau stdin non-standar untuk proses nyata.
Mikko Rantalainen
13

tl; dr: Kerang tidak melakukannya secara otomatis karena biaya melebihi kemungkinan manfaatnya.

Jawaban lain menunjukkan perbedaan teknis antara stdin menjadi pipa dan menjadi file. Dengan mengingat hal itu, shell dapat melakukan salah satu dari:

  1. Diimplementasikan catsebagai builtin, masih mempertahankan perbedaan file v. Pipe. Ini akan menghemat biaya eksekutif dan mungkin, mungkin garpu.
  2. Lakukan analisis penuh dari pipa dengan pengetahuan tentang berbagai perintah yang digunakan untuk melihat apakah file / pipa itu penting, kemudian bertindak berdasarkan itu.

Selanjutnya Anda harus mempertimbangkan biaya dan manfaat dari setiap pendekatan. Manfaatnya cukup sederhana:

  1. Dalam kedua kasus, hindari eksekutif (dari cat)
  2. Dalam kasus kedua, saat penggantian redirect dimungkinkan, menghindari garpu.
  3. Dalam kasus di mana Anda harus menggunakan pipa, itu mungkin menjadi mungkin kadang-kadang untuk menghindari garpu / vfork, tetapi sering tidak. Itu karena kebutuhan setara kucing untuk berjalan pada saat yang sama dengan sisa pipa.

Jadi Anda menghemat sedikit waktu & memori CPU, terutama jika Anda dapat menghindari garpu. Tentu saja, Anda hanya menghemat waktu & memori ini ketika fitur tersebut benar-benar digunakan. Dan Anda hanya benar-benar menghemat waktu fork / exec; dengan file yang lebih besar, waktunya sebagian besar waktu I / O (yaitu, kucing membaca file dari disk). Jadi Anda harus bertanya: seberapa sering catdigunakan (tidak berguna) dalam skrip shell di mana kinerja sebenarnya penting? Bandingkan dengan builtin shell umum lainnya seperti test- sulit dibayangkan catdigunakan (tidak berguna) bahkan sepersepuluh sering testdigunakan di tempat-tempat yang penting. Itu dugaan, saya belum mengukur, yang merupakan sesuatu yang ingin Anda lakukan sebelum upaya implementasi. (Atau sama halnya, meminta orang lain untuk mengimplementasikan misalnya permintaan fitur.)

Selanjutnya Anda bertanya: berapa biayanya. Dua biaya yang muncul dalam pikiran adalah (a) kode tambahan dalam shell, yang meningkatkan ukurannya (dan dengan demikian mungkin penggunaan memori), membutuhkan lebih banyak pekerjaan pemeliharaan, adalah tempat lain untuk bug, dll .; dan (b) mundur kejutan kompatibilitas, POSIX catmenghilangkan banyak fitur misalnya, GNU coreutils cat, jadi Anda harus berhati-hati persis apa yang catakan diterapkan oleh builtin.

  1. Opsi builtin tambahan mungkin tidak terlalu buruk - menambahkan satu lagi builtin di mana banyak sudah ada. Jika Anda memiliki data profil yang menunjukkan itu akan membantu, Anda mungkin bisa meyakinkan penulis shell favorit Anda untuk menambahkannya.

  2. Adapun untuk menganalisis pipa, saya tidak berpikir shell melakukan hal seperti ini saat ini (beberapa mengenali ujung pipa dan dapat menghindari percabangan). Pada dasarnya Anda akan menambahkan pengoptimal (primitif) ke shell; pengoptimal sering berubah menjadi kode rumit dan sumber banyak bug. Dan bug-bug itu bisa mengejutkan - sedikit perubahan pada skrip shell dapat berakhir dengan menghindari atau memicu bug.

Catatan tambahan: Anda dapat menerapkan analisis serupa untuk penggunaan kucing yang tidak berguna. Manfaat: lebih mudah dibaca (meskipun jika command1 akan mengambil file sebagai argumen, mungkin tidak). Biaya: garpu dan eksekutif tambahan (dan jika command1 dapat mengambil file sebagai argumen, mungkin pesan kesalahan lebih membingungkan). Jika analisis Anda memberi tahu Anda untuk menggunakan kucing yang tidak berguna, lanjutkan.

derobert
sumber
10

The catperintah dapat menerima -sebagai penanda untuk stdin . ( POSIX , " Jika file adalah '-', utilitas cat harus membaca dari input standar pada titik itu dalam urutan. ") Ini memungkinkan penanganan sederhana file atau stdin di mana jika tidak maka ini akan dianulir.

Pertimbangkan dua alternatif sepele ini, di mana argumen shell $1adalah -:

cat "$1" | nl    # Works completely transparently
nl < "$1"        # Fails with 'bash: -: No such file or directory'

Waktu lain catyang berguna adalah di mana ia sengaja digunakan sebagai larangan untuk mempertahankan sintaksis shell:

file="$1"
reader=cat
[[ $file =~ \.gz$ ]] && reader=zcat
[[ $file =~ \.bz2$ ]] && reader=bzcat
"$reader" "$file"

Akhirnya, saya percaya satu-satunya waktu UUOC benar-benar dapat dipanggil dengan benar adalah ketika catdigunakan dengan nama file yang dikenal sebagai file biasa (yaitu bukan perangkat atau pipa bernama), dan bahwa tidak ada bendera yang diberikan kepada perintah:

cat file.txt

Dalam situasi lain, sifat orop catitu sendiri mungkin diperlukan.

roaima
sumber
6

Perintah cat dapat melakukan hal-hal yang tidak dapat dilakukan oleh shell (atau setidaknya, tidak bisa dilakukan dengan mudah). Misalnya, Anda ingin mencetak karakter yang mungkin tidak terlihat, seperti tab, carriage return, atau baris baru. Ada * mungkin * cara untuk melakukannya dengan hanya perintah builtin shell, tapi saya tidak bisa memikirkan apa pun dari atas kepala saya. Versi GNU dari kucing dapat melakukannya dengan -Aargumen atau -v -E -Targumen (saya tidak tahu tentang versi kucing yang lain). Anda juga bisa mengawali setiap baris dengan menggunakan nomor baris -n(sekali lagi, IDK jika versi non-GNU dapat melakukan ini).

Keuntungan lain dari kucing adalah dapat dengan mudah membaca banyak file. Untuk melakukannya, seseorang cukup mengetik cat file1 file2 file3. Untuk melakukan hal yang sama dengan shell, semuanya akan menjadi rumit, meskipun loop yang dibuat dengan hati-hati kemungkinan besar dapat mencapai hasil yang sama. Yang mengatakan, apakah Anda benar-benar ingin meluangkan waktu untuk menulis loop seperti itu, ketika ada alternatif sederhana seperti itu? Bukan saya!

Membaca file dengan cat mungkin akan menggunakan CPU lebih sedikit daripada shell, karena cat adalah program yang sudah dikompilasi (pengecualian yang jelas adalah shell yang memiliki kucing builtin). Saat membaca sekelompok besar file, ini mungkin menjadi jelas, tetapi saya belum pernah melakukannya di komputer saya, jadi saya tidak bisa memastikan.

Perintah cat juga dapat berguna untuk memaksa perintah untuk menerima input standar jika tidak. Pertimbangkan yang berikut ini:

echo 8 | sleep

Angka "8" tidak akan diterima oleh perintah "sleep", karena tidak pernah benar-benar dimaksudkan untuk menerima input standar. Dengan demikian, tidur akan mengabaikan masukan itu, mengeluh tentang kurangnya argumen, dan keluar. Namun, jika satu jenis:

echo 8 | sleep $(cat)

Banyak cangkang akan memperluas ini menjadi sleep 8, dan tidur akan menunggu selama 8 detik sebelum keluar. Anda juga dapat melakukan sesuatu yang mirip dengan ssh:

command | ssh 1.2.3.4 'cat >> example-file'

Perintah ini dengan menambahkan file-contoh pada mesin dengan alamat 1.2.3.4 dengan apa pun yang dihasilkan dari "perintah".

Dan itu (mungkin) hanya menggaruk permukaan. Saya yakin saya bisa menemukan lebih banyak contoh kucing yang berguna jika saya mau, tetapi postingan ini cukup panjang. Jadi, saya akan menyimpulkan dengan mengatakan ini: meminta shell untuk mengantisipasi semua skenario ini (dan beberapa skenario lainnya) tidak benar-benar layak.

TSJNachos117
sumber
Saya akan mengakhiri kalimat terakhir dengan "tidak mudah untuk dilakukan"
Basile Starynkevitch
3

Ingatlah bahwa seorang pengguna dapat memiliki catdi $PATHdalamnya yang bukan POSIX cat(tapi mungkin beberapa varian yang dapat mencatat sesuatu di suatu tempat). Dalam hal ini, Anda tidak ingin shell untuk menghapusnya.

The PATH bisa berubah secara dinamis, dan kemudian cat bukan apa yang Anda percaya itu. Akan sangat sulit untuk menulis shell yang melakukan optimasi yang Anda impikan.

Juga, dalam praktiknya, cat adalah program yang cukup cepat. Ada beberapa alasan praktis (kecuali estetika) untuk menghindarinya.

Lihat juga pembicaraan hebat Parsing POSIX [s] oleh Yann Regis-Gianas di FOSDEM2018. Ini memberikan alasan bagus lainnya untuk menghindari melakukan apa yang Anda impikan dalam sebuah shell.

Jika kinerja benar-benar masalah untuk shell, seseorang akan mengusulkan shell yang menggunakan optimasi kompiler seluruh program canggih, analisis kode sumber statis, dan teknik kompilasi just-in-time (ketiga domain ini memiliki dekade perkembangan dan publikasi ilmiah dan berdedikasi konferensi, misalnya di bawah SIGPLAN ). Sayangnya, bahkan sebagai topik penelitian yang menarik, yang saat ini tidak didanai oleh lembaga penelitian atau pemodal ventura, dan saya menyimpulkan bahwa itu sama sekali tidak sepadan dengan usaha. Dengan kata lain, mungkin tidak ada pasar yang signifikan untuk mengoptimalkan cangkang . Jika Anda memiliki setengah juta euro untuk dibelanjakan pada penelitian seperti itu, Anda akan dengan mudah menemukan seseorang untuk melakukannya, dan saya percaya itu akan memberikan hasil yang bermanfaat.

Di sisi praktis, menulis ulang, untuk meningkatkan kinerjanya, skrip shell kecil (tidak berbaris) dalam bahasa scripting yang lebih baik (Python, AWK, Guile, ...) umumnya dilakukan. Dan tidak masuk akal (karena banyak alasan rekayasa perangkat lunak) untuk menulis skrip shell besar: ketika Anda menulis skrip shell melebihi seratus baris, Anda perlu mempertimbangkan untuk menulis ulang (bahkan untuk alasan keterbacaan dan pemeliharaan) dalam beberapa bahasa yang lebih cocok : sebagai bahasa pemrograman shell adalah yang sangat miskin. Namun, ada banyak skrip shell yang dihasilkan besar , dan untuk alasan yang baik (misalnya configureskrip yang dihasilkan autoconf GNU ).

Mengenai file tekstual yang besar, meneruskannya catsebagai argumen tunggal bukanlah praktik yang baik, dan sebagian besar sysadmin tahu bahwa (ketika skrip shell membutuhkan waktu lebih dari satu menit untuk dijalankan, Anda mulai mempertimbangkan untuk mengoptimalkannya). Untuk file gigabyte besar, catadalah tidak pernah alat yang baik untuk memproses mereka.

Basile Starynkevitch
sumber
3
"Cukup banyak alasan praktis untuk menghindarinya" - siapa pun yang menunggu untuk cat some-huge-log | tail -n 5berlari (di mana tail -n 5 some-huge-logbisa melompat langsung ke akhir, sedangkan catmembaca hanya dari depan ke belakang) akan tidak setuju.
Charles Duffy
Komentar memeriksa catfile teks besar dalam rentang puluhan GB (yang dibuat untuk pengujian) membutuhkan waktu agak lama. Tidak akan merekomendasikan.
Sergiy Kolodyazhnyy
1
BTW, re: "tidak ada pasar yang signifikan untuk mengoptimalkan shell" - ksh93 adalah shell yang mengoptimalkan, dan yang cukup bagus. Hal itu , untuk sementara, berhasil dijual sebagai produk komersial. (Sedihnya, mendapatkan lisensi komersial juga menjadikannya cukup ceruk bahwa klon yang ditulis dengan buruk dan penerus yang kurang mampu tetapi bebas biaya mengambil alih dunia di luar situs-situs yang bersedia membayar untuk lisensi, yang mengarah pada situasi yang kita alami. miliki hari ini).
Charles Duffy
(tidak menggunakan teknik spesifik yang Anda catat, tetapi terus terang, teknik-teknik itu tidak masuk akal mengingat model proses; teknik yang diterapkan adalah, baik, diterapkan dengan baik dan dengan efek yang baik ).
Charles Duffy
2

Menambahkan ke jawaban @Kusalananda (dan komentar @alephzero), kucing bisa apa saja:

alias cat='gcc -c'
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

atau

echo 'echo 1' > /usr/bin/cat
cat "$MYFILE" | command1 | command2 > "$OUTPUT"

Tidak ada alasan bahwa kucing (sendiri) atau / usr / bin / cat pada sistem sebenarnya adalah alat penggabung.

rampok
sumber
3
Selain perilaku catdidefinisikan oleh POSIX dan karenanya tidak boleh sangat berbeda.
roaima
2
@roaima: PATH=/home/Joshua/bin:$PATH cat ...Apakah Anda yakin tahu apa yang catdilakukan sekarang?
Joshua
1
@ Yaua tidak masalah. Kami berdua tahu catbisa ditimpa, tetapi kami juga tahu bahwa itu tidak boleh hanya diganti dengan yang lain. Komentar saya menunjukkan bahwa POSIX mengamanatkan perilaku (subset dari) tertentu yang secara wajar dapat diharapkan ada. Kadang-kadang saya telah menulis skrip shell yang memperluas perilaku utilitas standar. Dalam hal ini skrip shell bertindak dan berperilaku seperti alat yang diganti, kecuali bahwa ia memiliki kemampuan tambahan.
roaima
@ Joshua: Pada kebanyakan platform, shell tahu (atau bisa tahu) direktori mana yang dapat dieksekusi yang mengimplementasikan perintah POSIX. Jadi Anda bisa menunda substitusi sampai setelah ekspansi alias dan resolusi jalur, dan hanya melakukannya untuk /bin/cat. (Dan Anda akan menjadikannya opsi yang bisa Anda matikan.) Atau Anda akan membuat catshell built-in (yang mungkin kembali ke /bin/catbeberapa argumen?) Sehingga pengguna dapat mengontrol apakah mereka ingin versi eksternal normal atau tidak. cara, dengan enable cat. Seperti untuk kill. (Saya berpikir bahwa bash command catakan berhasil, tetapi itu tidak melewatkan builtin)
Peter Cordes
Jika Anda memberikan alias, shell akan tahu bahwa catdi lingkungan itu tidak lagi mengacu pada yang biasa cat. Tentunya, optimasi harus diimplementasikan setelah alias diproses. Saya menganggap shell built-in untuk mewakili perintah dalam direktori virtual yang selalu ditambahkan ke jalur Anda. Jika Anda ingin menghindari versi built-in shell dari perintah apa pun (misalnya test), Anda harus menggunakan varian dengan path.
Mikko Rantalainen
1

Dua kegunaan "tidak berguna" untuk kucing:

sort file.txt | cat header.txt - footer.txt | less

... di sini catdigunakan untuk mencampur input file dan pipa.

find . -name '*.info' -type f | sh -c 'xargs cat' | sort

... di sini xargsdapat menerima jumlah nama file yang hampir tak terbatas dan menjalankan catsebanyak yang diperlukan sambil menjadikan semuanya berperilaku seperti satu aliran. Jadi ini berfungsi untuk daftar file besar di mana penggunaan langsung xargs sorttidak.

tasket
sumber
Kedua kasus penggunaan ini akan dihindarkan dari remeh dengan membuat shell built-in step-in saja jika catdipanggil dengan satu argumen. Terutama kasus di mana shdilewatkan string dan xargsakan memanggil catlangsung tidak ada cara shell bisa menggunakan itu built-in implementasi.
Mikko Rantalainen
0

Selain dari hal-hal lain, cat-periksa akan menambah overhead kinerja tambahan dan kebingungan yang penggunaannya catsebenarnya tidak berguna, IMHO, karena pemeriksaan seperti itu bisa tidak efisien dan menciptakan masalah dengan catpenggunaan yang sah .

Ketika perintah berurusan dengan stream standar, mereka hanya perlu peduli membaca / menulis ke deskriptor file standar. Perintah dapat mengetahui apakah stdin dapat dicari / lseekable atau tidak, yang mengindikasikan pipa atau file.

Jika kita menambahkan ke campuran memeriksa proses apa yang sebenarnya menyediakan konten stdin, kita perlu menemukan proses di sisi lain pipa dan menerapkan optimasi yang sesuai. Ini dapat dilakukan dalam hal shell itu sendiri, seperti yang ditunjukkan dalam posting SuperUser oleh Kyle Jones, dan dalam hal shell itu

(find /proc -type l | xargs ls -l | fgrep 'pipe:[20043922]') 2>/dev/null

seperti yang ditunjukkan pada posting yang ditautkan. Ini adalah 3 perintah lagi ( fork()s dan s ekstra exec()) dan traversal rekursif (begitu banyak readdir()panggilan).

Dalam hal kode sumber C dan shell, shell sudah mengetahui proses anak, jadi tidak perlu untuk rekursi, tetapi bagaimana kita tahu kapan harus mengoptimalkan dan kapan catsebenarnya tidak berguna? Sebenarnya ada kegunaan berguna kucing , seperti

# adding header and footer to file
( cmd; cat file; cmd ) | cmd
# tr command does not accept files as arguments
cat log1 log2 log3 | tr '[:upper:]' '[:lower:]'

Mungkin akan sia-sia dan overhead yang tidak perlu untuk menambahkan optimasi seperti itu ke shell. Seperti jawaban Kusalanda sudah disebutkan, UUOC lebih tentang kurangnya pemahaman pengguna tentang bagaimana cara terbaik menggabungkan perintah untuk hasil terbaik.

Sergiy Kolodyazhnyy
sumber