GNU/Linux >> Belajar Linux >  >> Linux

Trik Bash Bodoh:Sejarah, menggunakan kembali argumen, file dan direktori, fungsi, dan banyak lagi

Sebagai administrator sistem, shell adalah bagian dari operasi sehari-hari. Kerang sering memberikan lebih banyak pilihan dan fleksibilitas daripada antarmuka pengguna grafis (GUI). Tugas berulang harian dapat dengan mudah diotomatisasi oleh skrip, atau tugas dapat dijadwalkan untuk dijalankan pada waktu tertentu di siang hari. Shell menyediakan cara yang nyaman untuk berinteraksi dengan sistem dan memungkinkan Anda melakukan lebih banyak dalam waktu yang lebih singkat. Ada banyak shell yang berbeda, termasuk Bash, zsh, tcsh, dan PowerShell.

Dalam posting blog dua bagian ini, saya membagikan beberapa kalimat Bash yang saya gunakan untuk mempercepat pekerjaan saya dan memberikan lebih banyak waktu untuk minum kopi. Dalam posting awal ini, saya akan membahas sejarah, argumen terakhir, bekerja dengan file dan direktori, membaca konten file, dan fungsi Bash. Di bagian kedua, saya akan memeriksa variabel shell, perintah find, deskriptor file, dan menjalankan operasi dari jarak jauh.

Gunakan perintah riwayat

history perintah adalah salah satu yang berguna. History memungkinkan saya untuk melihat perintah apa yang saya jalankan pada sistem atau argumen tertentu yang diteruskan ke perintah itu. Saya menggunakan history untuk menjalankan kembali perintah tanpa harus mengingat apapun.

Catatan perintah terbaru disimpan secara default di ~/.bash_history. Lokasi ini dapat diubah dengan memodifikasi variabel shell HISTFILE. Ada variabel lain, seperti HISTSIZE (baris untuk disimpan dalam memori untuk sesi saat ini) dan HISTFILESIZE (berapa banyak baris untuk disimpan dalam file riwayat). Jika Anda ingin tahu lebih banyak tentang history , lihat man bash .

Katakanlah saya menjalankan perintah berikut:

$> sudo systemctl status sshd

Bash memberi tahu saya bahwa layanan sshd tidak berjalan, jadi hal berikutnya yang ingin saya lakukan adalah memulai layanan. Saya telah memeriksa statusnya dengan perintah saya sebelumnya. Perintah itu disimpan di history , jadi saya bisa referensi itu. Saya cukup menjalankan:

$> !!:s/status/start/
sudo systemctl start sshd

Ekspresi di atas memiliki konten berikut:

  • !! - ulangi perintah terakhir dari sejarah
  • :s/status/start/ - pengganti status dengan mulai

Hasilnya adalah layanan sshd dimulai.

Selanjutnya, saya meningkatkan nilai HISTSIZE default dari 500 menjadi 5000 dengan menggunakan perintah berikut:

$> echo “HISTSIZE=5000” >> ~/.bashrc && source ~/.bashrc

Bagaimana jika saya ingin menampilkan tiga perintah terakhir dalam riwayat saya? Saya memasukkan:

$> history 3
 1002  ls
 1003  tail audit.log
 1004  history 3

Saya menjalankan tail di audit.log dengan mengacu pada nomor baris sejarah. Dalam hal ini, saya menggunakan baris 1003:

$> !1003
tail audit.log
..
..

Bayangkan Anda telah menyalin sesuatu dari terminal lain atau browser Anda dan Anda secara tidak sengaja menempelkan salinan tersebut (yang Anda miliki di buffer salinan) ke terminal. Baris-baris itu akan disimpan dalam riwayat, yang di sini adalah sesuatu yang tidak Anda inginkan. Jadi di situlah unset HISTFILE &&exit berguna

$> unset HISTFILE && exit

atau

$> kill -9 $$

Referensikan argumen terakhir dari perintah sebelumnya

Ketika saya ingin membuat daftar isi direktori untuk direktori yang berbeda, saya mungkin sering berpindah antar direktori. Ada trik bagus yang dapat Anda gunakan untuk merujuk ke argumen terakhir dari perintah sebelumnya. Misalnya:

$> pwd
/home/username/
$> ls some/very/long/path/to/some/directory
foo-file bar-file baz-file

Pada contoh di atas, /some/very/long/path/to/some/directory adalah argumen terakhir dari perintah sebelumnya.

Jika saya ingin cd (ubah direktori) ke lokasi itu, saya memasukkan sesuatu seperti ini:

$> cd $_

$> pwd
/home/username/some/very/long/path/to/some/directory

Sekarang cukup gunakan karakter tanda hubung untuk kembali ke tempat saya sebelumnya:

$> cd -
$> pwd
/home/username/

Mengerjakan file dan direktori

Bayangkan saya ingin membuat struktur direktori dan memindahkan banyak file yang memiliki ekstensi berbeda ke direktori ini.

Pertama, saya membuat direktori sekaligus:

$> mkdir -v dir_{rpm,txt,zip,pdf}
mkdir: created directory 'dir_rpm'
mkdir: created directory 'dir_txt'
mkdir: created directory 'dir_zip'
mkdir: created directory 'dir_pdf'

Selanjutnya, saya memindahkan file berdasarkan ekstensi file ke setiap direktori:

$> mv -- *.rpm dir_rpm/
$> mv -- *.pdf dir_pdf/
$> mv -- *.txt dir_txt/
$> mv -- *.zip dir_txt/

Karakter tanda hubung ganda -- berarti Akhir Pilihan. Bendera ini mencegah file yang dimulai dengan tanda hubung diperlakukan sebagai argumen.

Selanjutnya saya ingin mengganti/memindahkan semua file *.txt ke file *.log, jadi saya masukkan:

$> for f in ./*.txt; do mv -v ”$file” ”${file%.*}.log”; done
renamed './file10.txt' -> './file10.log'
renamed './file1.txt' -> './file1.log'
renamed './file2.txt' -> './file2.log'
renamed './file3.txt' -> './file3.log'
renamed './file4.txt' -> './file4.log'

Alih-alih menggunakan for loop di atas, saya dapat menginstal prename perintah dan capai tujuan di atas seperti ini:

$> prename -v 's/.txt/.log/' *.txt
file10.txt -> file10.log
file1.txt -> file1.log
file2.txt -> file2.log
file3.txt -> file3.log
file4.txt -> file4.log

Seringkali, ketika memodifikasi file konfigurasi, saya membuat salinan cadangan dari yang asli dengan menggunakan perintah salin dasar. Misalnya:

$> cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth0.back

Seperti yang Anda lihat, mengulangi seluruh jalur dan menambahkan .back ke file tidak begitu efisien dan mungkin rawan kesalahan. Ada cara yang lebih pendek dan lebih rapi untuk melakukan ini. Ini dia:

$> cp /etc/sysconfig/network-scripts/ifcfg-eth0{,.back}

Anda dapat melakukan pemeriksaan yang berbeda pada file atau variabel. Jalankan help test untuk informasi lebih lanjut.

Gunakan perintah berikut untuk mengetahui apakah suatu file adalah tautan simbolis:

$> [[ -L /path/to/file ]] && echo “File is a symlink”

Inilah masalah yang saya temui baru-baru ini. Saya ingin gunzip/untar banyak file sekaligus. Tanpa pikir panjang, saya mengetik:

$> tar zxvf *.gz

Hasilnya adalah:

tar: openvpn.tar.gz: Not found in archive
tar: Exiting with failure status due to previous errors

File tarnya adalah:

iptables.tar.gz
openvpn.tar.gz
…..

Mengapa tidak berhasil, dan mengapa ls -l *.gz bekerja sebagai gantinya? Di bawah tenda, terlihat seperti ini:

$> tar zxvf *.gz

Ditransformasikan sebagai berikut:

$> tar zxvf iptables.tar.gz openvpn.tar.gz
tar: openvpn.tar.gz: Not found in archive
tar: Exiting with failure status due to previous errors

tar perintah diharapkan untuk menemukan openvpn.tar.gz dalam iptables.tar.gz. Saya memecahkan ini dengan sederhana for lingkaran:

$> for f in ./*.gz; do tar zxvf "$f"; done
iptables.log
openvpn.log

Saya bahkan dapat membuat kata sandi acak dengan menggunakan Bash! Ini contohnya:

$> alphanum=( {a..z} {A..Z} {0..9} ); for((i=0;i<=${#alphanum[@]};i++)); do printf '%s' "${alphanum[@]:$((RANDOM%255)):1}"; done; echo

Berikut adalah contoh yang menggunakan OpenSSL:

$> openssl rand -base64 12
JdDcLJEAkbcZfDYQ

Membaca file baris demi baris

Asumsikan saya memiliki file dengan banyak alamat IP dan ingin beroperasi pada alamat IP tersebut. Misalnya, saya ingin menjalankan dig untuk mengambil informasi reverse-DNS untuk alamat IP yang tercantum dalam file. Saya juga ingin melewati alamat IP yang dimulai dengan komentar (# atau hashtag).

Saya akan menggunakan fileA sebagai contoh. Isinya adalah:

10.10.12.13  some ip in dc1
10.10.12.14  another ip in dc2
#10.10.12.15 not used IP
10.10.12.16  another IP

Saya dapat menyalin dan menempelkan setiap alamat IP, lalu menjalankan dig secara manual:

$> dig +short -x 10.10.12.13

Atau saya bisa melakukan ini:

$> while read -r ip _; do [[ $ip == \#* ]] && continue; dig +short -x "$ip"; done < ipfile

Bagaimana jika saya ingin menukar kolom di fileA? Misalnya, saya ingin meletakkan alamat IP di kolom paling kanan sehingga fileA terlihat seperti ini:

some ip in dc1 10.10.12.13
another ip in dc2 10.10.12.14
not used IP #10.10.12.15
another IP 10.10.12.16

Saya menjalankan:

$> while  read -r ip rest; do printf '%s %s\n' "$rest" "$ip"; done < fileA

Gunakan fungsi Bash

Fungsi di Bash berbeda dengan yang ditulis dengan Python, C, awk, atau bahasa lainnya. Di Bash, fungsi sederhana yang menerima satu argumen dan mencetak "Hello world" akan terlihat seperti ini:

func() { local arg=”$1”; echo “$arg” ; }

Saya dapat memanggil fungsi seperti ini:

$> func foo

Terkadang suatu fungsi memanggil dirinya sendiri secara rekursif untuk melakukan tugas tertentu. Misalnya:

func() { local arg="$@"; echo "$arg"; f "$arg"; }; f foo bar

Rekursi ini akan berjalan selamanya dan menggunakan banyak sumber daya. Di Bash, Anda dapat menggunakan FUNCNEST untuk membatasi rekursi. Dalam contoh berikut, saya menetapkan FUNCNEST=5 untuk membatasi rekursi menjadi lima.

func() { local arg="$@"; echo "$arg"; FUNCNEST=5; f "$arg"; }; f foo bar
foo bar
foo bar
foo bar
foo bar
foo bar
bash: f: maximum function nesting level exceeded (5)

Gunakan fungsi untuk mengambil file terbaru atau terlama

Berikut adalah contoh fungsi untuk menampilkan file terbaru di direktori tertentu:

latest_file()
{
  local f latest
  for f in "${1:-.}"/*
    do
      [[ $f -nt $latest ]] && latest="$f"
    done
   printf '%s\n' "$latest"
}

Fungsi ini menampilkan file tertua di direktori tertentu:

oldest_file()
{
  local f oldest
  for file in "${1:-.}"/*
    do
      [[ -z $oldest || $f -ot $oldest ]] && oldest="$f"
    done
  printf '%s\n' "$oldest"
}

Ini hanyalah beberapa contoh cara menggunakan fungsi di Bash tanpa menjalankan perintah eksternal lainnya.

Saya terkadang mendapati diri saya mengetik perintah berulang-ulang dengan banyak parameter. Salah satu perintah yang sering saya gunakan adalah kubectl (CLI Kubernetes). Saya lelah menjalankan perintah yang panjang ini! Berikut perintah aslinya:

$> kubectl -n my_namespace get pods

atau

$> kubectl -n my_namespace get rc,services

Sintaks ini mengharuskan saya untuk secara manual memasukkan -n my_namespace setiap kali saya menjalankan perintah. Ada cara yang lebih mudah untuk melakukannya menggunakan fungsi:

$> kubectl () { command kubectl -n my_namespace ”$@” ; }

Sekarang saya bisa menjalankan kubectl tanpa harus mengetik -n namespace setiap kali:

$> kubectl get pods

Saya dapat menerapkan teknik yang sama untuk perintah lain.

Menutup

Ini hanya beberapa trik luar biasa yang ada untuk Bash. Di bagian kedua, saya akan menunjukkan beberapa contoh lagi, termasuk penggunaan find dan eksekusi jarak jauh. Saya mendorong Anda untuk mempraktikkan trik ini untuk membuat tugas administrasi baris perintah Anda lebih mudah dan lebih akurat.

[ Kursus online gratis:Tinjauan teknis Red Hat Enterprise Linux. ]


Linux
  1. Temukan file dan direktori terbesar di Linux

  2. Ganti nama file dan direktori secara rekursif di bawah ubuntu / bash

  3. Mengatur ACL yang berbeda pada direktori dan file

  1. Temukan File dan Direktori di Linux Seperti Profesional

  2. bash - hapus semua direktori (dan konten) tetapi bukan file di pwd

  3. Tip dan trik rsync favorit

  1. Trik Bash yang lebih bodoh:Variabel, temukan, deskriptor file, dan operasi jarak jauh

  2. Cara Membuat dan Memanggil Fungsi di Bash

  3. Linux Hapus File dan Direktori