GNU/Linux >> Belajar Linux >  >> Ubuntu

Bagaimana Perintah (yaitu Grep) Tahu Kapan Dijalankan Sebagai Bagian Dari Perluasan Glob?

Sesuai pemahaman saya, glob wildcard ditafsirkan oleh Shell, yang kemudian menjalankan perintah yang diberikan untuk setiap nama file yang cocok. Misalkan saya memiliki file:abc1, abc2, and abc3 di direktori saya saat ini. Kemudian, misalnya, echo abc* akan bergema sekali untuk setiap nama file yang dimulai dengan 'abc'.

Namun, jika saya menjalankan grep 'foo' abc* , saya membayangkan ini harus dijalankan:

grep 'foo' abc1
grep 'foo' abc2
grep 'foo' abc3

Yang berarti saya harus mendapatkan output berikut (dengan asumsi semua file berisi satu baris yang mengatakan 'foo'):

foo
foo
foo

Namun, saya malah mendapatkan:

abc1:foo
abc2:foo
abc3:foo

Jadi saya pikir ada 2 kemungkinan penjelasan untuk ini. Pertama, entah bagaimana grep dapat mendeteksi bahwa itu digunakan dengan ekspresi glob dan merespons dengan mengeluarkan nama file sebelum kecocokan. Kedua, karena Anda dapat meneruskan banyak file ke grep, shell sebenarnya hanya menjalankan 1 perintah:

grep 'foo' abc1 abc2 abc3

Namun, ini hanya berfungsi karena grep menerima banyak file di akhir. Ada kemungkinan bahwa perintah lain hanya mengizinkan 1 file untuk dilewatkan. Jadi, jika Anda ingin menjalankan perintah untuk beberapa file yang cocok dengan glob, itu tidak akan berfungsi jika globbing bekerja melalui metode kedua yang dijelaskan di atas.

Bagaimanapun, dapatkah seseorang menjelaskan hal ini?

Terima kasih!

Jawaban yang Diterima:

Itulah triknya:perintah tidak tahu, shell yang melakukan tugasnya

Perhatikan misalnya grep 'abc' *.txt . Jika kami menjalankan jejak panggilan sistem, Anda akan melihat sesuatu seperti ini:

bash-4.3$ strace -e trace=execve grep "abc" *.txt > /dev/null
execve("/bin/grep", ["grep", "abc", "ADDA_converters.txt", "after.txt", "altera_license.txt", "altera.txt", "ANALOG_DIGITAL_NOTES.txt", "androiddev.txt", "answer2.txt", "answer.txt", "ANSWER.txt", "ascii.txt", "askubuntu-profile.txt", "AskUbuntu_Translators.txt", "a.txt", "bash_result.txt", ...], [/* 80 vars */]) = 0
+++ exited with 0 +++

Shell memperluas *.txt ke semua nama file di direktori saat ini yang diakhiri dengan .txt perpanjangan. Jadi secara efektif, shell Anda menerjemahkan grep 'abc' *.txt perintah ke grep 'abc' file1.txt file2.txt file3.txt . . . . Jadi, asumsi kedua Anda benar.

Asumsi pertama tidak benar – program tidak memiliki cara untuk mendeteksi glob. Dimungkinkan untuk melewati * sebagai argumen string ke perintah, tetapi tugas perintah adalah memutuskan apa yang harus dilakukan dengannya. Perluasan nama file, bagaimanapun, adalah milik shell Anda masing-masing seperti yang telah saya sebutkan.

Namun, ini hanya berfungsi karena grep menerima banyak file di akhir. Ada kemungkinan bahwa perintah lain hanya mengizinkan 1 file untuk diteruskan.

Tepat sekali! Program tidak membatasi jumlah argumen baris perintah yang dapat diterima (misalnya, dalam C yang merupakan larik string const char *args[] dan dalam python sys.argv[] ), tetapi mereka dapat mendeteksi panjang array itu atau apakah ada sesuatu yang tidak terduga dalam posisi array yang salah. grep tidak melakukan itu, dan menerima banyak file, yang memang dirancang.

Terkait:Setelah memutakhirkan ke Ubuntu 13.10, Firefox terkadang membuat komputer crash?

Di samping catatan, kutipan yang tidak tepat ditambah dengan globbing dengan grep terkadang bisa menjadi masalah. Pertimbangkan ini:

bash-4.3$ echo "one two" | strace -e trace=execve grep *est*
execve("/bin/grep", ["grep", "self_test.sh", "test.wxg"], [/* 80 vars */]) = 0
+++ exited with 1 +++

Pengguna yang tidak siap akan berharap bahwa grep akan cocok dengan baris apa pun dengan est huruf di dalamnya berasal dari pipa, tetapi perluasan nama file shell memutarbalikkan segalanya. Saya sering melihat ini terjadi pada orang yang melakukan ps aux | grep shell_script_name.sh , dan mereka berharap menemukan prosesnya berjalan, tetapi karena mereka menjalankan perintah dari direktori yang sama tempat skrip , perluasan nama file shell membuat grep perintah agar terlihat sangat berbeda di balik layar dari yang diharapkan pengguna.

Cara yang tepat adalah dengan menggunakan tanda kutip tunggal:

bash-4.3$ echo "one two" | strace -e trace=execve grep '*est*'
execve("/bin/grep", ["grep", "*est*"], [/* 80 vars */]) = 0
+++ exited with 1 +++

Ubuntu
  1. Cara menggunakan perintah grep Linux

  2. Bagaimana Menjalankan Perintah Asli Yang Berasal Dari Nama Yang Sama?

  3. Bagaimana Cara Menjalankan Aplikasi Untuk Waktu yang Ditetapkan Di Shell?

  1. Bagaimana Kami Menjalankan Perintah yang Disimpan Dalam Variabel?

  2. Bagaimana Cara Menjalankan Perintah Saat Konten Direktori Diperbarui?

  3. Bagaimana Cara Memastikan Wine Tidak Menjalankan File .exe Secara Otomatis?

  1. Bagaimana Cara Kerja Perintah Tee??

  2. Bagaimana Perintah Xdg-open Mengetahui Aplikasi Yang Digunakan Untuk Membuka File?

  3. Bagaimana Menyembunyikan Output Terminal Saat Menjalankan Perintah?