Trik puluhan dengan shell Linux yang bisa menghemat waktu Anda



  • Pertama-tama, Anda dapat membaca artikel ini dalam bahasa Rusia di sini .

Suatu malam, saya sedang membaca Menguasai ekspresi reguler oleh Jeffrey Friedl , saya menyadari bahwa bahkan jika Anda memiliki semua dokumentasi dan banyak pengalaman, mungkin ada banyak trik yang dikembangkan oleh orang yang berbeda dan dipenjara untuk diri mereka sendiri. Semua orang berbeda. Dan teknik yang jelas bagi orang-orang tertentu mungkin tidak jelas bagi orang lain dan terlihat seperti semacam sihir aneh bagi orang ketiga. Ngomong-ngomong, saya sudah menggambarkan beberapa momen seperti itu di sini (dalam bahasa Rusia) .

Untuk administrator atau pengguna, baris perintah tidak hanya alat yang dapat melakukan segalanya, tetapi juga alat yang sangat khusus yang dapat dikembangkan selamanya. Baru-baru ini ada artikel yang diterjemahkan tentang beberapa trik yang berguna di CLI. Tetapi saya merasa bahwa penerjemah tidak memiliki pengalaman yang cukup dengan CLI dan tidak mengikuti trik yang dijelaskan, begitu banyak hal penting yang bisa terlewatkan atau disalahpahami.

Di bawah cut - selusin trik di Linux shell dari pengalaman pribadi saya.

Catatan: Semua skrip dan contoh dalam artikel itu secara khusus disederhanakan sebanyak mungkin - jadi mungkin Anda dapat menemukan beberapa trik yang terlihat sama sekali tidak berguna - mungkin inilah alasannya. Tetapi bagaimanapun juga, bagikan pendapat Anda dalam komentar!

1. Pisahkan string dengan ekspansi variabel


Orang sering menggunakan cut atau awk hanya untuk mengurangi bagian dari string dengan pola atau dengan pemisah.
Juga, banyak orang menggunakan operasi bash substring menggunakan $ {VARIABLE: start_position: length}, yang bekerja sangat cepat.

Tapi bash menyediakan cara ampuh untuk memanipulasi dengan string teks menggunakan #, ##,% dan %% - itu disebut ekspansi variabel bash .
Dengan menggunakan sintaks ini, Anda dapat memotong yang diperlukan oleh pola tanpa menjalankan perintah eksternal, sehingga akan bekerja sangat cepat.

Contoh di bawah ini menunjukkan cara mendapatkan kolom ketiga (shell) dari string di mana nilai dipisahkan oleh titik dua "username: homedir: shell" menggunakan cut atau menggunakan ekspansi variabel (kami menggunakan perintah *: mask dan perintah ##, yang berarti: cut semua karakter ke kiri hingga titik dua terakhir ditemukan):

$ STRING="username:homedir:shell" $ echo "$STRING"|cut -d ":" -f 3 shell $ echo "${STRING##*:}" shell 

Opsi kedua tidak memulai proses anak ( potong ), dan tidak menggunakan pipa sama sekali, yang seharusnya bekerja lebih cepat. Dan jika Anda menggunakan subsistem bash di windows, di mana pipa hampir tidak bergerak, perbedaan kecepatan akan menjadi signifikan .

Mari kita lihat contoh di Ubuntu - jalankan perintah kami dalam satu lingkaran sebanyak 1000 kali

 $ cat test.sh #!/usr/bin/env bash STRING="Name:Date:Shell" echo "using cut" time for A in {1..1000} do cut -d ":" -f 3 > /dev/null <<<"$STRING" done echo "using ##" time for A in {1..1000} do echo "${STRING##*:}" > /dev/null done 

Hasil
 $ ./test.sh using cut real 0m0.950s user 0m0.012s sys 0m0.232s using ## real 0m0.011s user 0m0.008s sys 0m0.004s 

Perbedaannya adalah beberapa lusin kali!

Tentu saja, contoh di atas terlalu buatan. Dalam contoh nyata kita tidak akan bekerja dengan string statis, kita ingin membaca file nyata. Dan untuk perintah ' cut ', kita hanya mengarahkan / etc / passwd ke sana. Dalam kasus ##, kita harus membuat loop dan membaca file menggunakan perintah ' baca ' internal. Jadi siapa yang akan memenangkan kasus ini?

 $ cat test.sh #!/usr/bin/env bash echo "using cut" time for count in {1..1000} do cut -d ":" -f 7 </etc/passwd > /dev/null done echo "using ##" time for count in {1..1000} do while read do echo "${REPLY##*:}" > /dev/null done </etc/passwd done 
Hasil
 $ ./test.sh $ ./test.sh using cut real 0m0.827s user 0m0.004s sys 0m0.208s using ## real 0m0.613s user 0m0.436s sys 0m0.172s 
Tidak ada komentar =)

Beberapa contoh lagi:

Ekstrak nilai setelah karakter yang sama:

 $ VAR="myClassName = helloClass" $ echo ${VAR##*= } helloClass 

Ekstrak teks dalam tanda kurung:

 $ VAR="Hello my friend (enemy)" $ TEMP="${VAR##*\(}" $ echo "${TEMP%\)}" enemy 

2. Bash pelengkapan otomatis dengan tab


paket bash-completion adalah bagian dari hampir setiap distribusi Linux. Anda dapat mengaktifkannya di /etc/bash.bashrc atau /etc/profile.d/bash_completion.sh, tetapi biasanya sudah diaktifkan secara default. Secara umum, autocomplete adalah salah satu momen nyaman pertama di shell Linux yang pertama kali ditemui oleh pendatang baru.

Tetapi fakta bahwa tidak semua orang menggunakan semua fitur bash-completion, dan menurut saya sama sekali sia-sia. Misalnya tidak semua orang tahu, bahwa pelengkapan otomatis berfungsi tidak hanya dengan nama file, tetapi juga dengan alias, nama variabel, nama fungsi, dan untuk beberapa perintah bahkan dengan argumen. Jika Anda menggali skrip pelengkapan otomatis, yang sebenarnya merupakan skrip shell, Anda bahkan dapat menambahkan pelengkapan otomatis untuk aplikasi atau skrip Anda sendiri.
Tapi mari kita kembali ke alias.

Anda tidak perlu mengedit variabel PATH atau membuat file di direktori yang ditentukan untuk menjalankan alias. Anda hanya perlu menambahkannya ke skrip profil atau startup dan menjalankannya dari mana saja.

Biasanya kami menggunakan huruf kecil untuk file dan direktori di * nix, jadi bisa sangat nyaman untuk membuat alias huruf besar - dalam hal ini bash-completion akan menebak perintah Anda hampir dengan satu huruf:

 $ alias TAsteriskLog="tail -f /var/log/asteriks.log" $ alias TMailLog="tail -f /var/log/mail.log" $ TA[tab]steriksLog $ TM[tab]ailLog 

3. Bash pelengkapan otomatis dengan tab - bagian 2


Untuk kasus yang lebih rumit, mungkin Anda ingin meletakkan skrip pribadi Anda ke $ HOME / bin.
Tapi kami memiliki fungsi di bash.

Fungsi tidak memerlukan path atau file yang terpisah. Dan (perhatian) bash-completion bekerja dengan fungsi juga.

Mari kita buat fungsi LastLogin di .profile (jangan lupa memuat ulang .profile):

 function LastLogin { STRING=$(last | head -n 1 | tr -s " " " ") USER=$(echo "$STRING"|cut -d " " -f 1) IP=$(echo "$STRING"|cut -d " " -f 3) SHELL=$( grep "$USER" /etc/passwd | cut -d ":" -f 7) echo "User: $USER, IP: $IP, SHELL=$SHELL" } 

(Sebenarnya tidak ada yang penting apa fungsi ini lakukan, itu hanya contoh skrip yang dapat kita tempatkan ke skrip terpisah atau bahkan ke alias, tetapi fungsi bisa lebih baik) .

Di konsol (harap dicatat bahwa nama fungsi memiliki huruf besar pertama untuk mempercepat penyelesaian-bash):

 $ L[tab]astLogin User: saboteur, IP: 10.0.2.2, SHELL=/bin/bash 

4.1. Data sensitif


Jika Anda meletakkan spasi di depan perintah apa pun di konsol, itu tidak akan muncul di riwayat perintah, jadi jika Anda perlu memasukkan kata sandi teks pada perintah, itu adalah cara yang baik untuk menggunakan fitur ini - lihat contoh di bawah ini, echo "halo 2 " tidak akan muncul dalam riwayat:

 $ echo "hello" hello $ history 2 2011 echo "hello" 2012 history 2 $ echo "my password secretmegakey" # there are two spaces before 'echo' my password secretmegakey $ history 2 2011 echo "hello" 2012 history 2 

Itu opsional
Biasanya diaktifkan secara default, tetapi Anda dapat mengonfigurasi perilaku ini dalam variabel berikut:

export HISTCONTROL = ignoreboth


4.2. Data sensitif dalam argumen baris perintah


Anda ingin menyimpan beberapa skrip shell di git untuk membagikannya di server, atau mungkin itu adalah bagian dari skrip startup aplikasi. Dan Anda ingin skrip ini akan terhubung ke database atau melakukan hal lain yang memerlukan kredensial.

Tentu saja itu ide buruk untuk menyimpan kredensial dalam skrip itu sendiri, karena git tidak aman.

Biasanya Anda dapat menggunakan variabel, yang sudah ditentukan pada lingkungan target, dan skrip Anda tidak akan berisi kata sandi itu sendiri.

Misalnya, Anda dapat membuat skrip kecil di setiap lingkungan dengan 700 izin dan menyebutnya dengan menggunakan perintah sumber dari skrip utama:

 secret.sh PASSWORD=LOVESEXGOD 

 myapp.sh source ~/secret.sh sqlplus -l user/"$PASSWORD"@database:port/sid @mysqfile.sql 

Tapi itu tidak aman.

Jika orang lain dapat masuk ke host Anda, ia bisa menjalankan perintah ps dan melihat proses sqlplus Anda dengan seluruh argumen baris perintah termasuk kata sandi. Jadi, alat yang aman biasanya harus dapat membaca kata sandi / kunci / data sensitif langsung dari file.

Misalnya - ssh aman bahkan tidak memiliki opsi untuk memberikan kata sandi di baris perintah. Tapi dia bisa membaca kunci ssh dari file (dan Anda dapat mengatur izin aman pada file kunci ssh).

Dan wget yang tidak aman memiliki opsi "--password" yang memungkinkan Anda memberikan kata sandi di baris perintah. Dan sepanjang waktu wget akan berjalan, semua orang dapat menjalankan perintah ps dan melihat kata sandi yang Anda berikan.

Selain itu, jika Anda memiliki banyak data sensitif, dan Anda ingin mengontrolnya dari git, satu-satunya cara adalah enkripsi. Jadi, Anda menempatkan ke setiap lingkungan target hanya kata sandi utama, dan semua data lain yang dapat Anda enkripsi dan masukkan ke git. Dan Anda dapat bekerja dengan data terenkripsi dari baris perintah, menggunakan antarmuka CLI openssl. Ini adalah contoh untuk mengenkripsi dan mendekripsi dari baris perintah:

File secret.key berisi kunci utama - satu baris:

 $ echo "secretpassword" > secret.key; chmod 600 secret.key 

Mari kita gunakan aes-256-cbc untuk mengenkripsi string:

 $ echo "string_to_encrypt" | openssl enc -pass file:secret.key -e -aes-256-cbc -a U2FsdGVkX194R0GmFKCL/krYCugS655yLhf8aQyKNcUnBs30AE5lHN5MXPjjSFML 

Anda dapat meletakkan string terenkripsi ini ke file konfigurasi apa pun yang disimpan di git, atau tempat lain - tanpa secret.key hampir tidak mungkin untuk mendekripsi.
Untuk mendekripsi jalankan perintah yang sama cukup ganti -e dengan -d:

 $ echo 'U2FsdGVkX194R0GmFKCL/krYCugS655yLhf8aQyKNcUnBs30AE5lHN5MXPjjSFML' | openssl enc -pass file:secret.key -d -aes-256-cbc -a string_to_encrypt 

5. Perintah grep


Semua harus tahu perintah grep. Dan bersikap ramah dengan ekspresi reguler. Dan seringkali Anda dapat menulis sesuatu seperti:

 tail -f application.log | grep -i error 

Atau bahkan seperti ini:

 tail -f application.log | grep -i -P "(error|warning|failure)" 

Tetapi jangan lupa bahwa grep memiliki banyak pilihan yang bagus. Misalnya -v, yang mengembalikan pencarian Anda dan menampilkan semua pesan kecuali "info":

 tail -f application.log | grep -v -i "info" 

Barang tambahan:

Opsi -P sangat berguna, karena secara default grep menggunakan "ekspresi reguler dasar:", dan -P memungkinkan PCRE yang bahkan tidak tahu tentang pengelompokan.
-Saya mengabaikan kasus.
- line parses buffer-line segera daripada menunggu untuk mencapai standar buffer 4k (berguna untuk tail -f | grep).

Jika Anda tahu ekspresi reguler dengan baik, dengan --only-matching / -o Anda benar-benar dapat melakukan hal-hal hebat dengan memotong teks. Bandingkan saja dua perintah berikutnya untuk mengekstrak shell myuser:

 $ grep myuser /etc/passwd| cut -d ":" -f 7 $ grep -Po "^myuser(:.*){5}:\K.*" /etc/passwd 

Perintah kedua terlihat lebih terkompilasi, tetapi hanya menjalankan grep daripada grep dan cut , sehingga akan memakan waktu lebih sedikit untuk eksekusi.

6. Cara mengurangi ukuran file log


Di * nix, jika Anda menghapus file log, yang saat ini digunakan oleh aplikasi, Anda tidak bisa menghapus semua log, Anda dapat mencegah aplikasi untuk menulis log baru sampai restart.

Karena deskriptor file tidak membuka nama file, tetapi struktur iNode, dan aplikasi akan terus menulis ke deskriptor file ke file, yang tidak memiliki entri direktori, dan file tersebut akan dihapus secara otomatis setelah aplikasi dihentikan oleh sistem file ( aplikasi Anda dapat buka dan tutup file log setiap kali ingin menulis sesuatu untuk menghindari masalah seperti itu, tetapi ini memengaruhi kinerja ).

Jadi, cara menghapus file log tanpa menghapusnya:

 echo "" > application.log 

Atau kita bisa menggunakan perintah truncate:

 truncate --size=1M application.log 

Sebutkan, perintah terpotong itu akan menghapus sisa file, sehingga Anda akan kehilangan peristiwa log terbaru. Lihat contoh lain cara menyimpan 1000 baris terakhir:

 echo "$(tail -n 1000 application.log)" > application.log 

PS Di Linux kami memiliki rotatelog layanan standar. Anda dapat menambahkan log ke truncate / rotate otomatis atau menggunakan pustaka log yang ada yang dapat melakukannya untuk Anda (seperti log4j di java).

7. Watch memperhatikan Anda!


Ada situasi ketika Anda sedang menunggu beberapa acara selesai. Misalnya, ketika pengguna lain masuk ke shell (Anda terus-menerus mengeksekusi perintah siapa ), atau seseorang harus menyalin file ke mesin Anda menggunakan scp atau ftp dan Anda sedang menunggu penyelesaiannya (berulang puluhan kali).

Dalam kasus seperti itu, Anda dapat menggunakan

 watch <command> 

Secara default, akan dieksekusi setiap 2 detik dengan pra-hapus layar sampai Ctrl + C ditekan. Anda dapat mengkonfigurasi seberapa sering harus dieksekusi.

Ini sangat berguna ketika Anda ingin menonton log langsung.

8. Urutan bash


Ada konstruk yang sangat berguna untuk membuat rentang. Sebagai contoh, bukannya sesuatu seperti ini:

 for srv in 1 2 3 4 5; do echo "server${srv}";done server1 server2 server3 server4 server5 

Anda dapat menulis yang berikut ini:

 for srv in server{1..5}; do echo "$srv";done server1 server2 server3 server4 server5 

Anda juga dapat menggunakan perintah seq untuk menghasilkan rentang yang diformat. Sebagai contoh, kita dapat menggunakan seq untuk membuat nilai whitch akan secara otomatis disesuaikan dengan lebar (00, 01 bukannya 0, 1):

 for srv in $(seq -w 5 10); do echo "server${srv}";done server05 server06 server07 server08 server09 server10 

Contoh lain dengan substitusi perintah - ganti nama file. Untuk mendapatkan nama file tanpa ekstensi, kami menggunakan perintah ' basename ':

 for file in *.txt; do name=$(basename "$file" .txt);mv $name{.txt,.lst}; done 

Juga lebih singkat dengan '%':

 for file in *.txt; do mv ${file%.txt}{.txt,.lst}; done 

PS Sebenarnya untuk mengganti nama file Anda dapat mencoba alat ' rename ' yang memiliki banyak pilihan.

Contoh lain - mari buat struktur untuk proyek java baru:

 mkdir -p project/src/{main,test}/{java,resources} 

Hasil
 project/ !--- src/ |--- main/ | |-- java/ | !-- resources/ !--- test/ |-- java/ !-- resources/ 

9. ekor, banyak file, banyak pengguna ...


Saya telah menyebutkan multitail untuk membaca file dan menonton beberapa log langsung. Tapi itu tidak disediakan secara default, dan izin untuk menginstal sesuatu tidak selalu tersedia.

Tetapi ekor standar dapat melakukannya juga:

 tail -f /var/logs/*.log 

Ingat juga tentang pengguna, yang menggunakan alias 'tail -f' untuk menonton log aplikasi.
Beberapa pengguna dapat menonton file log secara bersamaan menggunakan 'tail -f'. Beberapa dari mereka tidak terlalu akurat dengan sesi mereka. Mereka bisa meninggalkan 'tail -f' di latar belakang untuk beberapa alasan dan melupakannya.

Jika aplikasi di-restart, ada proses 'tail -f' yang sedang berjalan yang menonton file log yang tidak ada dapat digantung selama beberapa hari atau bahkan berbulan-bulan.

Biasanya itu bukan masalah besar, tapi tidak rapi.

Jika Anda menggunakan alias untuk menonton log, Anda dapat memodifikasi alias ini dengan opsi --pid:

 alias TFapplog='tail -f --pid=$(cat /opt/app/tmp/app.pid) /opt/app/logs/app.log' 

Dalam hal itu, semua ekor akan secara otomatis dihentikan ketika aplikasi target akan dimulai ulang.

10. Buat file dengan ukuran yang ditentukan


dd adalah salah satu alat paling populer untuk bekerja dengan data blok dan biner. Misalnya buat file 1 MB diisi dengan nol akan:

 dd if=/dev/zero of=out.txt bs=1M count=10 

Tapi saya sarankan menggunakan fallocate :

 fallocate -l 10M file.txt 

Pada sistem file, yang mendukung fungsi alokasi (xfs, ext4, Btrfs ...), fallocate akan dieksekusi secara instan, tidak seperti alat dd. Selain itu, mengalokasikan berarti alokasi blok nyata, bukan membuat file cadangan.

11. xargs


Banyak orang tahu perintah xargs populer. Tetapi tidak semua dari mereka menggunakan dua opsi berikut, yang dapat sangat meningkatkan skrip Anda.

Pertama - Anda bisa mendapatkan daftar argumen yang sangat panjang untuk diproses, dan bisa melebihi panjang baris perintah (secara default ~ 4 kb).

Tetapi Anda dapat membatasi eksekusi menggunakan opsi -n, sehingga xargs akan menjalankan perintah beberapa kali, mengirimkan sejumlah argumen pada suatu waktu:

 $ # lets print 5 arguments and send them to echo with xargs: $ echo 1 2 3 4 5 | xargs echo 1 2 3 4 5 $ # now let's repeat, but limit argument processing by 3 per execution $ echo 1 2 3 4 5 | xargs -n 3 echo 1 2 3 4 5 

Maju terus. Memproses daftar panjang bisa memakan banyak waktu, karena berjalan dalam satu utas. Tetapi jika kita memiliki beberapa inti, kita dapat memberi tahu xargs untuk berjalan secara paralel:

 echo 1 2 3 4 5 6 7 8 9 10| xargs -n 2 -P 3 echo 

Pada contoh di atas, kami memberi tahu xargs untuk memproses daftar dalam 3 utas; setiap utas akan mengambil dan memproses 2 argumen per eksekusi. Jika Anda tidak tahu berapa banyak inti yang Anda miliki, mari optimalkan ini menggunakan " nproc ":

 echo 1 2 3 4 5 6 7 8 9 10 | xargs -n 2 -P $(nproc) echo 

12. tidur? sementara baca!


Beberapa saat Anda perlu menunggu beberapa detik. Atau tunggu input pengguna dengan baca:

 read -p "Press any key to continue " -n 1 

Tetapi Anda bisa menambahkan opsi batas waktu untuk membaca perintah, dan skrip Anda akan dijeda untuk jumlah detik tertentu, tetapi dalam hal eksekusi interaktif, pengguna dapat dengan mudah melewati menunggu.

 read -p "Press any key to continue (auto continue in 30 seconds) " -t 30 -n 1 

Jadi Anda bisa melupakan perintah tidur.

Saya curiga tidak semua trik saya terlihat menarik, tetapi bagi saya sepertinya selusin adalah angka yang baik untuk diisi.

Saat ini saya mengucapkan selamat tinggal, dan saya akan berterima kasih untuk berpartisipasi dalam survei.

Tentu saja bebas untuk membahas hal di atas dan membagikan trik keren Anda di komentar!

Source: https://habr.com/ru/post/id444890/


All Articles