13 alat pengolah kata berbasis shell

Berikut adalah bagian dari buku masa depan, Alat Dasar dan Praktek untuk Pengembang Perangkat Lunak Novice, oleh Balthazar Ruberol dan Etienne Broad . Buku ini harus membantu mendidik generasi pengembang yang lebih muda. Ini akan mencakup topik-topik seperti menguasai konsol, mengatur dan bekerja secara efisien dalam shell perintah, kode versi menggunakan gitdasar-dasar SQL, alat-alat seperti Make, jqdan ekspresi reguler, dasar-dasar jaringan, serta praktik terbaik untuk pengembangan dan kolaborasi perangkat lunak. Para penulis saat ini bekerja keras dalam proyek ini dan mengundang semua orang untuk berpartisipasi dalam milis .

Kandungan



Pemrosesan Teks Shell


Salah satu alasan yang membuat shell perintah alat yang tak ternilai adalah sejumlah besar perintah pengolah kata dan kemampuan untuk dengan mudah menggabungkannya ke dalam pipa, membuat template pemrosesan yang kompleks. Perintah-perintah ini membuat banyak tugas sepele untuk menganalisis teks dan data, mengonversi data di antara berbagai format, menyaring string, dll.

Saat bekerja dengan data teks, prinsip utamanya adalah memecah masalah kompleks menjadi banyak yang lebih kecil - dan menyelesaikannya dari mereka menggunakan alat khusus.

Buat setiap program melakukan satu hal dengan baik - The Fundamentals of Unix Philosophy

Contoh-contoh dalam bab ini mungkin tampak sedikit dibuat-buat pada pandangan pertama, tetapi ini dilakukan dengan sengaja. Masing-masing alat dirancang untuk memecahkan satu masalah kecil. Namun, ketika digabungkan, mereka menjadi sangat kuat.

Kami akan melihat beberapa perintah pemrosesan teks yang paling umum dan berguna dalam shell perintah dan menunjukkan alur kerja nyata yang menghubungkannya bersama. Saya sarankan melihat mana tim ini untuk melihat luasnya kemungkinan yang Anda inginkan.

Contoh file CSV tersedia online . Anda dapat mengunduhnya untuk memeriksa materi.

kucing


Perintah ini catdigunakan untuk menyusun daftar satu atau lebih file dan menampilkan isinya di layar.

$ cat Documents/readme
Thanks again for reading this book!
I hope you're following so far!

$ cat Documents/computers
Computers are not intelligent
They're just fast at making dumb things.

$ cat Documents/readme Documents/computers
Thanks again for reading this book!
I hope you are following so far!

Computers are not intelligent
They're just fast at making dumb things.

kepala


headmencetak n baris pertama dalam file. Ini bisa sangat berguna untuk melihat file dengan struktur dan format yang tidak diketahui tanpa mengisi seluruh konsol dengan banyak teks.

$ head -n 2 metadata.csv
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name
mysql.galera.wsrep_cluster_size,gauge,,node,,The current number of nodes in the Galera cluster.,0,mysql,galera cluster size

Jika -ntidak ditentukan, headcetak sepuluh baris pertama dari file atau aliran input yang ditentukan.

ekor


tail- analog head, hanya menampilkan n baris terakhir dalam file.

$ tail -n 1 metadata.csv
mysql.performance.queries,gauge,,query,second,The rate of queries.,0,mysql,queries

Jika Anda ingin mencetak semua baris yang terletak setelah baris ke-n (termasuk itu), Anda dapat menggunakan argumen -n +n.

$ tail -n +42 metadata.csv
mysql.replication.slaves_connected,gauge,,,,Number of slaves connected to a replication master.,0,mysql,slaves connected
mysql.performance.queries,gauge,,query,second,The rate of queries.,0,mysql,queries

Ada 43 baris dalam file kita, oleh karena itu tail -n +42hanya menampilkan baris ke-42 dan ke-43 darinya.

Jika parameter -ntidak ditentukan, itu tailakan menampilkan sepuluh baris terakhir di file yang ditentukan atau aliran input.

tail -fatau tail --followtampilkan baris terakhir dalam file dan setiap baris baru saat mereka ditulis ke file. Ini sangat berguna untuk melihat aktivitas secara real time, misalnya, apa yang dicatat dalam log server web, dll.

toilet


wc(jumlah kata) menampilkan jumlah karakter ( -c), kata ( -w) atau baris ( -l) dalam file atau aliran yang ditentukan.

$ wc -l metadata.csv
43  metadata.csv
$ wc -w metadata.csv
405 metadata.csv
$ wc -c metadata.csv
5094 metadata.csv

Secara default, semua hal di atas ditampilkan.

$ wc metadata.csv
43     405    5094 metadata.csv

Jika data teks dialihkan atau dialihkan ke stdin, hanya penghitung yang ditampilkan.

$ cat metadata.csv | wc
43     405    5094
$ cat metadata.csv | wc -l
43
$ wc -w < metadata.csv
405

grep


grep- Ini adalah senar pisau penyaringan pisau Swiss sesuai dengan pola yang diberikan.

Misalnya, kita dapat menemukan semua kemunculan kata mutex dalam file.

$ grep mutex metadata.csv
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits
mysql.innodb.mutex_spin_rounds,gauge,,event,second,The rate of mutex spin rounds.,0,mysql,mutex spin rounds
mysql.innodb.mutex_spin_waits,gauge,,event,second,The rate of mutex spin waits.,0,mysql,mutex spin waits

grepdapat memproses file yang ditentukan sebagai argumen atau aliran teks yang diteruskan ke sana stdin. Dengan demikian, kita dapat menggabungkan beberapa perintah grepuntuk memfilter teks lebih lanjut. Pada contoh berikut, kami memfilter baris dalam file kami metadata.csvuntuk menemukan baris yang berisi mutex dan OS .

$ grep mutex metadata.csv | grep OS
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits

Mari kita pertimbangkan beberapa opsi grepdan perilakunya.

grep -vMelakukan pencocokan terbalik: memfilter string yang tidak cocok dengan pola argumen.

$ grep -v gauge metadata.csv
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name

grep -iMelakukan pencocokan tidak sensitif huruf besar / kecil. Contoh berikut grep -i osmenemukan OS dan os .

$ grep -i os metadata.csv
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits
mysql.innodb.os_log_fsyncs,gauge,,write,second,The rate of fsync writes to the log file.,0,mysql,log fsyncs

grep -l Daftar file yang mengandung kecocokan.

$ grep -l mysql metadata.csv
metadata.csv

Tim grep -cmenghitung berapa kali sampel ditemukan.

$ grep -c select metadata.csv
3

grep -r secara rekursif mencari file di direktori kerja saat ini dan semua subdirektori.

$ grep -r are ~/Documents
/home/br/Documents/computers:Computers are not intelligent
/home/br/Documents/readme:I hope you are following so far!

grep -w hanya menampilkan seluruh kata yang cocok.

$ grep follow ~/Documents/readme
I hope you are following so far!
$ grep -w follow ~/Documents/readme
$

memotong


cutmengekstrak bagian dari file (atau, seperti biasa, aliran input). Perintah mendefinisikan pemisah bidang (yang memisahkan kolom) menggunakan opsi -d, dan nomor kolom untuk mengambil menggunakan opsi -f.

Misalnya, perintah berikut mengambil kolom pertama dari lima baris terakhir file CSV kami.

$ tail -n 5 metadata.csv | cut -d , -f 1
mysql.performance.user_time
mysql.replication.seconds_behind_master
mysql.replication.slave_running
mysql.replication.slaves_connected
mysql.performance.queries

Karena kita berurusan dengan CSV, kolom dipisahkan oleh koma, dan opsi bertanggung jawab untuk mengambil kolom pertama -f 1.

Anda dapat memilih kolom pertama dan kedua menggunakan opsi -f 1,2.

$ tail -n 5 metadata.csv | cut -d , -f 1,2
mysql.performance.user_time,gauge
mysql.replication.seconds_behind_master,gauge
mysql.replication.slave_running,gauge
mysql.replication.slaves_connected,gauge
mysql.performance.queries,gauge

tempel


paste menggabungkan dua file berbeda menjadi satu file multi-kolom.

$ cat ingredients
eggs
milk
butter
tomatoes
$ cat prices
1$
1.99$
1.50$
2$/kg
$ paste ingredients prices
eggs    1$
milk    1.99$
butter  1.50$
tomatoes    2$/kg

Secara default, ini pastemenggunakan pembatas tab, tetapi dapat diubah menggunakan parameter -d.

$ paste ingredients prices -d:
eggs:1$
milk:1.99$
butter:1.50$
tomatoes:2$/kg

Kasus penggunaan umum lainnya paste adalah menggabungkan semua baris dalam aliran atau file menggunakan pembatas yang ditentukan, menggunakan kombinasi dari -sdan -d.

$ paste -s -d, ingredients
eggs,milk,butter,tomatoes

Jika suatu parameter ditentukan sebagai file input -, maka itu akan dibaca sebagai gantinya stdin.

$ cat ingredients | paste -s -d, -
eggs,milk,butter,tomatoes

menyortir


Perintah sortsebenarnya mengurutkan data (dalam file atau aliran input yang ditentukan).

$ cat ingredients
eggs
milk
butter
tomatoes
salt
$ sort ingredients
butter
eggs
milk
salt
tomatoes

sort -r melakukan penyortiran terbalik.

$ sort -r ingredients
tomatoes
salt
milk
eggs
butter

sort -n Urutkan bidang berdasarkan nilai aritmatika mereka.

$ cat numbers
0
2
1
10
3
$ sort numbers
0
1
10
2
3
$ sort -n numbers
0
1
2
3
10

uniq


uniq Mendeteksi dan memfilter garis identik yang berdekatan dalam file atau aliran input yang ditentukan.

$ cat duplicates
and one
and one
and two
and one
and two
and one, two, three
$ uniq duplicates
and one
and two
and one
and two
and one, two, three

Karena hanya uniqmenyaring garis yang berdekatan , duplikat mungkin masih tetap ada di data kami. Untuk memfilter semua baris yang sama dari suatu file, Anda harus terlebih dahulu mengurutkan isinya.

$ sort duplicates | uniq
and one
and one, two, three
and two

uniq -c di awal setiap baris memasukkan jumlah kemunculannya.

$ sort duplicates | uniq -c
   3 and one
   1 and one, two, three
   2 and two

uniq -u Hanya menampilkan string unik.

$ sort duplicates | uniq -u
and one, two, three

Catatan. uniqIni sangat berguna dalam kombinasi dengan pengurutan, karena pipa | sort | uniqmemungkinkan Anda untuk menghapus semua baris duplikat dalam file atau streaming.

awk


awk- Ini sedikit lebih dari sekedar alat pengolah kata: pada kenyataannya, ia memiliki bahasa pemrograman keseluruhan . Apa yang awk benar - benar baik adalah memecah file menjadi kolom, dan itu melakukannya dengan kecemerlangan khusus ketika spasi dan tab dicampur dalam file.

$ cat -t multi-columns
John Smith    Doctor^ITardis
Sarah-James Smith^I    Companion^ILondon
Rose Tyler   Companion^ILondon

Catatan. cat -tmenampilkan tab sebagai ^I.

Seperti yang Anda lihat, kolom dipisahkan oleh spasi atau tab, dan tidak selalu dengan jumlah spasi yang sama. cuttidak berguna di sini karena hanya berfungsi dengan satu karakter pemisah. Tetapi awkmudah untuk menangani file seperti itu.

awk '{ print $n }'menampilkan kolom ke-n dalam teks.

$ cat multi-columns | awk '{ print $1 }'
John
Sarah-James
Rose
$ cat multi-columns | awk '{ print $3 }'
Doctor
Companion
Companion
$ cat multi-columns | awk '{ print $1,$2 }'
John Smith
Sarah-James Smith
Rose Tyler

Meskipun awkmampu melakukan lebih banyak, output dari speaker mungkin 99% dari kasus penggunaan dalam kasus pribadi saya.

Catatan. { print $NF }menampilkan kolom terakhir berturut-turut.

tr


trsingkatan menerjemahkan . Perintah ini menggantikan satu karakter dengan yang lain. Ia bekerja dengan karakter atau kelas karakter seperti huruf kecil, diketik, spasi, alfanumerik, dll.

Pada input standar, ia tr <char1> <char2>menggantikan semua kemunculan <char1> dengan <char2>.

$ echo "Computers are fast" | tr a A
computers Are fAst

trdapat menerjemahkan kelas karakter menggunakan notasi [:class:]. Daftar lengkap kelas yang tersedia dijelaskan pada halaman manual tr, tetapi beberapa ditunjukkan di sini.

[:space:]mewakili semua jenis ruang, dari ruang sederhana hingga tab atau baris baru.

$ echo "computers are fast" | tr '[:space:]' ','
computers,are,fast,%

Semua karakter, seperti spasi, dipisahkan oleh koma. Perhatikan bahwa karakter %di akhir output menunjukkan tidak adanya penghentian baris baru. Memang, karakter ini juga dikonversi menjadi koma.

[:lower:]mewakili semua karakter huruf kecil, dan [:upper:] semua karakter huruf besar. Dengan demikian, transformasi di antara mereka menjadi sepele.

$ echo "computers are fast" | tr '[:lower:]' '[:upper:]'
COMPUTERS ARE FAST
$ echo "COMPUTERS ARE FAST" | tr '[:upper:]' '[:lower:]'
computers are fast

tr -c SET1 SET2Mengonversi karakter apa pun yang tidak termasuk dalam SET1 ke karakter dalam SET2. Dalam contoh berikut, semua karakter kecuali vokal yang ditunjukkan diganti dengan spasi.

$ echo "computers are fast" | tr -c '[aeiouy]' ' '
 o  u e   a e  a

tr -dMenghapus karakter yang ditentukan, tetapi tidak menggantikannya. Ini setara tr <char> ''.

$ echo "Computers Are Fast" | tr -d '[:lower:]'
C A F

trjuga dapat mengganti rentang karakter, misalnya, semua huruf antara a dan e atau semua angka antara 1 dan 8, menggunakan notasi s-e, di mana s karakter awal, dan e akhir.

$ echo "computers are fast" | tr 'a-e' 'x'
xomputxrs xrx fxst
$ echo "5uch l337 5p34k" | tr '1-4' 'x'
5uch lxx7 5pxxk

Perintah tr -s string1memampatkan semua kemunculan banyak karakter string1dalam satu tunggal. Salah satu kegunaan yang paling berguna tr -sadalah mengganti beberapa ruang berurutan dengan satu ruang.

$ echo "Computers         are       fast" | tr -s ' '
Computers are fast

melipat


Perintah ini foldmenciutkan semua jalur input dengan lebar yang ditentukan. Misalnya, dapat berguna untuk memastikan bahwa teks sesuai dengan tampilan kecil. Jadi, fold -w nsusun string dengan lebar n karakter.

$ cat ~/Documents/readme | fold -w 16
Thanks again for
 reading this bo
ok!
I hope you're fo
llowing so far!

Perintah ini fold -sakan memecah garis hanya pada karakter spasi. Itu dapat dikombinasikan dengan yang sebelumnya untuk membatasi string ke jumlah karakter yang ditentukan.

Thanks again
for reading
this book!
I hope you're
following so
far!

sed


sedAdalah editor aliran non-interaktif yang digunakan untuk mengonversi teks dalam aliran input baris demi baris. Sebagai input, baik file atau, atau stdinpada output, file atau stdout.

Perintah editor dapat menyertakan satu atau lebih alamat , fungsi, dan parameter . Jadi, perintahnya adalah sebagai berikut:

[address[,address]]function[arguments]

Meskipun sedmenjalankan banyak fungsi, kami hanya akan mempertimbangkan mengganti teks sebagai salah satu kasus penggunaan yang paling umum.

Penggantian Teks


Perintah penggantian adalah sedsebagai berikut:

s/PATTERN/REPLACEMENT/[options]

Contoh : mengganti instance kata pertama di setiap baris dalam file:

$ cat hello
hello hello
hello world!
hi
$ cat hello | sed 's/hello/Hey I just met you/'
Hey I just met you hello
Hey I just met you world
hi

Kita melihat bahwa pada baris pertama hanya instance pertama yang diganti hello. Untuk mengganti semua kemunculan hellodi semua lini, Anda dapat menggunakan opsi g(berarti global ).

$ cat hello | sed 's/hello/Hey I just met you/g'
Hey I just met you Hey I just met you
Hey I just met you world
hi

sedmemungkinkan Anda untuk menggunakan pembatas kecuali /, yang terutama meningkatkan keterbacaan jika ada garis miring dalam argumen perintah itu sendiri.

$ cat hello | sed 's@hello@Hey I just met you@g'
Hey I just met you Hey I just met you
Hey I just met you world
hi

Alamatnya memberi tahu editor tentang baris atau rentang baris mana yang harus diganti.

$ cat hello | sed '1s/hello/Hey I just met you/g'
Hey I just met you hello
hello world
hi
$ cat hello | sed '2s/hello/Hey I just met you/g'
hello hello
Hey I just met you  world
hi

Alamat 1menunjukkan ganti hellopada Hey I just met youdi baris pertama. Kita dapat menentukan kisaran alamat dalam notasi <start>,<end>, di mana itu <end>bisa berupa nomor baris atau $, yaitu, baris terakhir dalam file.

$ cat hello | sed '1,2s/hello/Hey I just met you/g'
Hey I just met you Hey I just met you
Hey I just met you world
hi
$ cat hello | sed '2,3s/hello/Hey I just met you/g'
hello hello
Hey I just met you world
hi
$ cat hello | sed '2,$s/hello/Hey I just met you/g'
hello hello
Hey I just met you world
hi

Secara default, ia sedmenghasilkan hasilnya sendiri stdout, tetapi juga dapat mengedit file asli dengan opsi -i.

$ sed -i '' 's/hello/Bonjour/' sed-data
$ cat sed-data
Bonjour hello
Bonjour world
hi

Catatan. Di Linux, cukup -i. Tetapi pada macOS, perilaku perintah sedikit berbeda, jadi -iAnda perlu menambahkan setelahnya ''.

Contoh nyata


Penyaringan CSV dengan grep dan awk


$ grep -w gauge metadata.csv | awk -F, '{ if ($4 == "query") { print $1, "per", $5 } }'
mysql.performance.com_delete per second
mysql.performance.com_delete_multi per second
mysql.performance.com_insert per second
mysql.performance.com_insert_select per second
mysql.performance.com_replace_select per second
mysql.performance.com_select per second
mysql.performance.com_update per second
mysql.performance.com_update_multi per second
mysql.performance.questions per second
mysql.performance.slow_queries per second
mysql.performance.queries per second

Dalam contoh ini grep, file metadata.csvpertama-tama memfilter baris yang berisi kata gauge, lalu yang dengan querykolom keempat, dan menampilkan nama metrik (kolom 1) dengan nilai yang sesuai per_unit_name(kolom 5).

Menampilkan alamat IPv4 yang terkait dengan antarmuka jaringan


$ ifconfig en0 | grep inet | grep -v inet6 | awk '{ print $2 }'
192.168.0.38

Perintah ifconfig <interface name>menampilkan informasi pada antarmuka jaringan yang ditentukan. Contohnya:

en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    ether 19:64:92:de:20:ba
    inet6 fe80::8a3:a1cb:56ae:7c7c%en0 prefixlen 64 secured scopeid 0x7
    inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255
    nd6 options=201<PERFORMNUD,DAD>
    media: autoselect
    status: active

Kemudian jalankan grepuntuk inet, yang akan menghasilkan dua baris korespondensi.

$ ifconfig en0 | grep inet
    inet6 fe80::8a3:a1cb:56ae:7c7c%en0 prefixlen 64 secured scopeid 0x7
    inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255

Kemudian, gunakan grep -vkecualikan baris dengan ipv6.

$ ifconfig en0 | grep inet | grep -v inet6
inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255

Akhirnya, dengan bantuan, kami awkmeminta kolom kedua di baris ini: ini adalah alamat IPv4 yang terkait dengan antarmuka jaringan kami en0.

$ ifconfig en0 | grep inet | grep -v inet6 | awk '{ print $2 }'
192.168.0.38

Catatan. Saya ditawari untuk diganti dengan grep inet | grep -v inet6tim yang andal awk:

$ ifconfig en0 | awk ' $1 == "inet" { print $2 }'
192.168.0.38

Itu lebih pendek dan secara khusus ditargetkan untuk IPv4 dengan kondisi tersebut $1 == "inet".

Mengambil nilai dari file konfigurasi


$ grep 'editor =' ~/.gitconfig  | cut -d = -f2 | sed 's/ //g'
/usr/bin/vim

Dalam file konfigurasi git dari pengguna saat ini, cari nilai editor =, potong karakter =, ekstrak kolom kedua dan hapus semua spasi di sekitar.

$ grep 'editor =' ~/.gitconfig
     editor = /usr/bin/vim
$ grep 'editor =' ~/.gitconfig  | cut -d'=' -f2
 /usr/bin/vim
$ grep 'editor =' ~/.gitconfig  | cut -d'=' -f2 | sed 's/ //'
/usr/bin/vim

Ekstrak IP dari file log


Kode nyata berikut mencari pesan di log basis data Too many connections from(diikuti dengan alamat IP) dan menampilkan sepuluh penyusup utama.

$ grep 'Too many connections from' db.log | \
  awk '{ print $12 }' | \
  sed 's@/@@' | \
  sort | \
  uniq -c | \
  sort -rn | \
  head -n 10 | \
  awk '{ print $2 }'
   10.11.112.108
   10.11.111.70
   10.11.97.57
   10.11.109.72
   10.11.116.156
   10.11.100.221
   10.11.96.242
   10.11.81.68
   10.11.99.112
   10.11.107.120

Mari kita lihat apa yang dilakukan pipa ini. Pertama, seperti apa garis dalam log itu.

$ grep "Too many connections from" db.log | head -n 1
2020-01-01 08:02:37,617 [myid:1] - WARN  [NIOServerCxn.Factory:1.2.3.4/1.2.3.4:2181:NIOServerCnxnFactory@193] - Too many connections from /10.11.112.108 - max is 60

Ini kemudian awk '{ print $12 }'mengekstrak alamat IP dari string.

$ grep "Too many connections from" db.log | awk '{ print $12 }'
/10.11.112.108
...

Perintah sed 's@/@@'menghapus garis miring awal.

$ grep "Too many connections from" db.log | awk '{ print $12 }' | sed 's@/@@'
10.11.112.108
...

Catatan. Seperti yang kita lihat sebelumnya, sedAnda dapat menggunakan pemisah apa pun di. Meskipun biasanya digunakan sebagai pemisah /, di sini kami mengganti karakter khusus ini, yang akan sedikit mengganggu keterbacaan ekspresi substitusi.

sed 's/\///'

sort | uniq -c mengurutkan alamat IP dalam urutan leksikografis, dan kemudian menghapus duplikat, menambahkan jumlah entri sebelum setiap alamat IP.

$ grep 'Too many connections from' db.log | \
  awk '{ print $12 }' | \
  sed 's@/@@' | \
  sort | \
  uniq -c
   1379 10.11.100.221
   1213 10.11.103.168
   1138 10.11.105.177
    946 10.11.106.213
   1211 10.11.106.4
   1326 10.11.107.120
   ...

sort -rn | head -n 10mengurutkan garis dengan jumlah kemunculan, secara numerik dan dalam urutan terbalik, sehingga pelanggar utama ditampilkan terlebih dahulu, di mana 10 garis ditampilkan. Perintah terakhir awk { print $2 }mengambil sendiri alamat IP.

$ grep 'Too many connections from' db.log | \
  awk '{ print $12 }' | \
  sed 's@/@@' | \
  sort | \
  uniq -c | \
  sort -rn | \
  head -n 10 | \
  awk '{ print $2 }'
  10.11.112.108
  10.11.111.70
  10.11.97.57
  10.11.109.72
  10.11.116.156
  10.11.100.221
  10.11.96.242
  10.11.81.68
  10.11.99.112
  10.11.107.120

Mengganti nama fungsi dalam file sumber


Bayangkan kita sedang mengerjakan proyek dan ingin mengganti nama fungsi yang tidak disebutkan namanya (atau kelas, variabel, dll.) Di file sumber. Anda dapat melakukan ini dengan perintah sed -iyang menggantikan langsung di file asli.

$ cat izk/utils.py
def bool_from_str(s):
    if s.isdigit():
        return int(s) == 1
    return s.lower() in ['yes', 'true', 'y']

$ sed -i 's/def bool_from_str/def is_affirmative/' izk/utils.py
$ cat izk/utils.py
def is_affirmative(s):
    if s.isdigit():
        return int(s) == 1
    return s.lower() in ['yes', 'true', 'y']

Catatan. Di macOS, sed -igunakan saja sed -i ''.

Namun, kami mengganti nama fungsi hanya di file asli. Ini akan memecah impor bool_from_strdalam file lain apa pun karena fungsi ini tidak lagi ditentukan. Kita perlu menemukan cara untuk mengganti nama di bool_from_strseluruh proyek kita. Ini dapat dicapai menggunakan perintah grep, sedserta loop foratau menggunakan xargs.

Pendalaman: siklus fordanxargs


Untuk mengganti semua kemunculan dalam proyek kami bool_from_str, Anda harus terlebih dahulu menemukannya secara rekursif grep -r.

$ grep -r bool_from_str .
./tests/test_utils.py:from izk.utils import bool_from_str
./tests/test_utils.py:def test_bool_from_str(s, expected):
./tests/test_utils.py:    assert bool_from_str(s) == expected
./izk/utils.py:def bool_from_str(s):
./izk/prompt.py:from .utils import bool_from_str
./izk/prompt.py:                    default = bool_from_str(os.environ[envvar])

Karena kami hanya tertarik pada file yang cocok, Anda juga harus menggunakan opsi -l/--files-with-matches:

-l, --files-with-matches
        Only the names of files containing selected lines are written to standard out-
        put.  grep will only search a file until a match has been found, making
        searches potentially less expensive.  Pathnames are listed once per file
        searched.  If the standard input is searched, the string ``(standard input)''
        is written.

$ grep -r --files-with-matches bool_from_str .
./tests/test_utils.py
./izk/utils.py
./izk/prompt.py

Kemudian kita dapat menggunakan perintah xargsuntuk melakukan tindakan dari setiap baris output (yaitu, semua file yang mengandung baris bool_from_str).

$ grep -r --files-with-matches bool_from_str . | \
  xargs -n 1 sed -i 's/bool_from_str/is_affirmative/'

Opsi -n 1menunjukkan bahwa setiap baris dalam output harus menjalankan perintah terpisah sed.

Kemudian perintah berikut dijalankan:

$ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/prompt.py

Jika perintah yang Anda panggil xargs(dalam kasus kami sed) mendukung banyak argumen, maka Anda harus membuang argumen -n 1untuk kinerja.

grep -r --files-with-matches bool_from_str . | xargs sed -i 's/bool_from_str/is_affirmative/'

Perintah ini kemudian akan dieksekusi

$ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py ./izk/utils.py ./izk/prompt.py

Catatan. Dapat seddilihat dari sinopsis di halaman manual bahwa tim dapat mengambil beberapa argumen.

SYNOPSIS
     sed [-Ealn] command [file ...]
     sed [-Ealn] [-e command] [-f command_file] [-i extension] [file ...]

Memang, seperti yang kita lihat di bab sebelumnya, itu file ...berarti bahwa beberapa argumen diterima, yang merupakan nama file.

Kami melihat bahwa penggantian dilakukan untuk semua kejadian bool_from_str.

$ grep -r is_affirmative .
./tests/test_utils.py:from izk.utils import is_affirmative
./tests/test_utils.py:def test_is_affirmative(s, expected):
./tests/test_utils.py:    assert is_affirmative(s) == expected
./izk/utils.py:def is_affirmative(s):
./izk/prompt.py:from .utils import is_affirmative
./izk/prompt.py:                    default = is_affirmative(os.environ[envvar])

Seperti yang sering terjadi, ada beberapa cara untuk mencapai hasil yang sama. Sebagai gantinya, xargskami dapat menggunakan loop foruntuk beralih di atas garis dalam daftar dan mengambil tindakan pada setiap item. Loop ini memiliki sintaks berikut:

for item in list; do
    command $item
done

Jika kita membungkus perintah kami grepdi $(), maka shell akan melaksanakannya dalam subkulit , yang hasilnya kemudian akan diulang dalam satu lingkaran for.

$ for file in $(grep -r --files-with-matches bool_from_str .); do
  sed -i 's/bool_from_str/is_affirmative/' $file
done

Perintah ini akan dieksekusi

$ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/prompt.py

Sintaks loop fortampaknya lebih jelas bagi saya daripada itu xargs, tetapi yang terakhir dapat mengeksekusi perintah secara paralel menggunakan parameter -P n, di mana njumlah maksimum perintah paralel dieksekusi pada saat yang sama, yang dapat memberikan keuntungan kinerja.

Ringkasan


Semua alat ini membuka seluruh dunia kemungkinan, karena memungkinkan Anda untuk mengekstraksi dan mengubah data, membuat seluruh jaringan pipa dari tim yang mungkin tidak pernah dimaksudkan untuk bekerja bersama. Masing-masing dari mereka melakukan fungsi yang relatif kecil (menyortir sort, menggabungkan cat, menyaring grep, mengedit sed, memotong cut, dll.).

Tugas apa pun yang menyertakan teks dapat direduksi menjadi saluran tugas yang lebih kecil, yang masing-masing melakukan tindakan sederhana dan mentransfer hasilnya ke tugas berikutnya.

Sebagai contoh, jika kita ingin tahu berapa banyak alamat IP unik dalam file log, dan agar alamat IP ini selalu muncul di kolom yang sama, maka kita dapat menjalankan urutan perintah berikut:

  • grep string yang cocok dengan pola string dengan alamat IP
  • temukan kolom dengan alamat IP, ekstrak dengan awk
  • urutkan daftar alamat IP menggunakan sort
  • hapus duplikat yang berdekatan dengan uniq
  • hitung jumlah baris (mis. alamat IP unik) menggunakan wc -l

Karena ada banyak alat pengolah kata asli dan pihak ketiga, ada juga banyak cara untuk memecahkan masalah.

Contoh-contoh dalam artikel ini dibuat-buat, tetapi saya sarankan Anda membaca artikel yang luar biasa "Alat baris perintah bisa 235 kali lebih cepat daripada kelompok Hadoop Anda" untuk mendapatkan gagasan tentang seberapa berguna dan kuat perintah ini sebenarnya dan apa masalah sebenarnya mereka dapat memutuskan.

Apa berikutnya


  1. Hitung jumlah file dan direktori yang ada di direktori home Anda.
  2. .
  3. , .
  4. . .



ยซ ยป (Essential Tools and Practices for the Aspiring Software Developer) , . , , , , git, SQL, Make, jq , , .

, !

All Articles