GNU/Linux >> Znalost Linux >  >> Linux

Stupid Bash triky:Historie, opětovné použití argumentů, souborů a adresářů, funkcí a další

Jako správce systému jsou shelly součástí každodenních operací. Shelly často poskytují více možností a flexibility než grafické uživatelské rozhraní (GUI). Denně se opakující úkoly lze snadno automatizovat pomocí skriptů nebo lze úkoly naplánovat tak, aby se spouštěly v určitou dobu během dne. Shell poskytuje pohodlný způsob interakce se systémem a umožňuje vám udělat více za kratší dobu. Existuje mnoho různých shellů, včetně Bash, zsh, tcsh a PowerShell.

V tomto dvoudílném blogovém příspěvku sdílím některé z Bashových jednorázových vložek, které používám k urychlení mé práce a ponechání více času na pití kávy. V tomto úvodním příspěvku se budu věnovat historii, posledním argumentům, práci se soubory a adresáři, čtení obsahu souborů a funkcím Bash. Ve druhé části prozkoumám proměnné shellu, příkaz find, deskriptory souborů a vzdálené provádění operací.

Použijte příkaz historie

history příkaz je šikovný. History umožňuje vidět, jaké příkazy jsem spustil na konkrétním systému nebo jaké argumenty byly tomuto příkazu předány. Používám history znovu spustit příkazy, aniž byste si museli něco pamatovat.

Záznam posledních příkazů je standardně uložen v ~/.bash_history. Toto umístění lze změnit úpravou proměnné shellu HISTFILE. Existují další proměnné, jako je HISTSIZE (řádky k uložení do paměti pro aktuální relaci) a HISTFILESIZE (kolik řádků zachovat v souboru historie). Pokud se chcete dozvědět více o history , viz man bash .

Řekněme, že spustím následující příkaz:

$> sudo systemctl status sshd

Bash mi říká, že služba sshd neběží, takže další věc, kterou chci udělat, je spustit službu. Zkontroloval jsem jeho stav pomocí předchozího příkazu. Tento příkaz byl uložen v history , takže na to mohu odkazovat. Jednoduše spustím:

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

Výše uvedený výraz má následující obsah:

  • !! - opakujte poslední příkaz z historie
  • :s/status/start/ – nahraďte stav s start

Výsledkem je spuštění služby sshd.

Dále zvýším výchozí hodnotu HISTSIZE z 500 na 5000 pomocí následujícího příkazu:

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

Co když chci zobrazit poslední tři příkazy v historii? Zadávám:

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

Spouštím tail na audit.log odkazem na číslo řádku historie. V tomto případě používám řádek 1003:

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

Představte si, že jste něco zkopírovali z jiného terminálu nebo vašeho prohlížeče a omylem vložíte kopii (kterou máte ve vyrovnávací paměti kopírování) do terminálu. Tyto řádky budou uloženy v historii, což je něco, co nechcete. Takže tam zrušte nastavení HISTFILE &&exit přijde vhod

$> unset HISTFILE && exit

nebo

$> kill -9 $$

Odkaz na poslední argument předchozího příkazu

Když chci vypsat obsah adresáře pro různé adresáře, mohu mezi adresáři poměrně často přecházet. Existuje pěkný trik, který můžete použít k odkazování na poslední argument předchozího příkazu. Například:

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

Ve výše uvedeném příkladu /some/very/long/path/to/some/directory je posledním argumentem předchozího příkazu.

Pokud chci cd (změnit adresář) do tohoto umístění, zadám něco takového:

$> cd $_

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

Nyní jednoduše použijte pomlčku, abyste se vrátili tam, kde jsem byl:

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

Práce se soubory a adresáři

Představte si, že chci vytvořit adresářovou strukturu a do těchto adresářů přesunout hromadu souborů s různými příponami.

Nejprve vytvořím adresáře najednou:

$> 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'

Dále přesunu soubory na základě přípony souboru do každého adresáře:

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

Dvojité pomlčky -- střední konec možností. Tento příznak zabraňuje tomu, aby byly soubory, které začínají pomlčkou, považovány za argumenty.

Dále chci nahradit/přesunout všechny soubory *.txt do souborů *.log, takže zadám:

$> 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'

Místo použití for smyčky výše, mohu nainstalovat prename příkaz a dosáhnout výše uvedeného cíle takto:

$> 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

Často při úpravě konfiguračního souboru vytvořím záložní kopii původního pomocí příkazu pro základní kopírování. Například:

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

Jak vidíte, opakování celé cesty a připojení .back k souboru není tak efektivní a pravděpodobně náchylné k chybám. Existuje kratší a přehlednější způsob, jak to udělat. Tady to je:

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

Můžete provádět různé kontroly souborů nebo proměnných. Spusťte help test pro více informací.

Chcete-li zjistit, zda je soubor symbolickým odkazem, použijte následující příkaz:

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

Zde je problém, na který jsem nedávno narazil. Chtěl jsem gunzip/rozbalit spoustu souborů najednou. Bez přemýšlení jsem napsal:

$> tar zxvf *.gz

Výsledek byl:

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

Soubory tar byly:

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

Proč to nefungovalo a proč by ls -l *.gz místo toho pracovat? Pod kapotou to vypadá takto:

$> tar zxvf *.gz

Transformuje se následovně:

$> 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 očekává se, že příkaz najde openvpn.tar.gz v rámci iptables.tar.gz. Vyřešil jsem to jednoduchým for smyčka:

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

Mohu dokonce generovat náhodná hesla pomocí Bash! Zde je příklad:

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

Zde je příklad, který používá OpenSSL:

$> openssl rand -base64 12
JdDcLJEAkbcZfDYQ

Čtení souboru řádek po řádku

Předpokládejme, že mám soubor s mnoha IP adresami a chci na těchto IP adresách pracovat. Například chci spustit dig k načtení reverzních informací DNS pro adresy IP uvedené v souboru. Chci také přeskočit IP adresy, které začínají komentářem (# nebo hashtag).

Jako příklad použiji soubor A. Jeho obsah je:

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

Mohl bych zkopírovat a vložit každou IP adresu a poté spustit dig ručně:

$> dig +short -x 10.10.12.13

Nebo bych mohl udělat toto:

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

Co když chci zaměnit sloupce v souboru A? Například chci umístit IP adresy do sloupce úplně vpravo, aby souborA vypadal takto:

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

Běžím:

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

Používejte funkce Bash

Funkce v Bash se liší od funkcí napsaných v Pythonu, C, awk nebo jiných jazycích. V Bash by jednoduchá funkce, která akceptuje jeden argument a vypíše „Hello world“, vypadala takto:

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

Funkci mohu zavolat takto:

$> func foo

Někdy se funkce vyvolá rekurzivně, aby provedla určitý úkol. Například:

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

Tato rekurze bude běžet navždy a bude využívat spoustu zdrojů. V Bash můžete použít FUNCNEST k omezení rekurze. V následujícím příkladu jsem nastavil FUNCNEST=5, abych omezil rekurzi na pět.

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)

Použijte funkci k načtení nejnovějšího nebo nejstaršího souboru

Zde je ukázková funkce pro zobrazení nejnovějšího souboru v určitém adresáři:

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

Tato funkce zobrazí nejstarší soubor v určitém adresáři:

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

Toto je jen několik příkladů, jak používat funkce v Bash bez vyvolání dalších externích příkazů.

Někdy se přistihnu, jak znovu a znovu zadávám příkaz se spoustou parametrů. Jeden příkaz, který často používám, je kubectl (Kubernetes CLI). Už mě nebaví spouštět tento dlouhý příkaz! Zde je původní příkaz:

$> kubectl -n my_namespace get pods

nebo

$> kubectl -n my_namespace get rc,services

Tato syntaxe vyžaduje, abych ručně zahrnul -n my_namespace pokaždé, když spustím příkaz. Existuje jednodušší způsob, jak to udělat pomocí funkce:

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

Nyní mohu spustit kubectl aniž byste museli zadávat -n namespace pokaždé:

$> kubectl get pods

Mohu použít stejnou techniku ​​na další příkazy.

Sbalit

Toto je jen několik vynikajících triků, které pro Bash existují. Ve druhé části ukážu několik dalších příkladů, včetně použití funkce find a vzdáleného provádění. Doporučuji vám procvičit si tyto triky, aby byly vaše úkoly správy příkazového řádku jednodušší a přesnější.

[ Bezplatný online kurz:Technický přehled Red Hat Enterprise Linux. ]


Linux
  1. Další hloupé Bashovy triky:Proměnné, hledání, deskriptory souborů a vzdálené operace

  2. Najděte největší soubory a adresáře v Linuxu

  3. Jak vytvářet a volat funkce v Bash

  1. Linux Odstraňte soubory a adresáře

  2. Nastavení různých ACL na adresáře a soubory

  3. Oblíbené rsync tipy a triky

  1. Najděte soubory a adresáře v Linuxu jako profík

  2. Přejmenujte soubory a adresáře rekurzivně pod ubuntu /bash

  3. bash - odstraní všechny adresáře (a obsah), ale ne soubory v pwd