GNU/Linux >> Tutoriels Linux >  >> Linux

Astuces Stupid Bash :historique, réutilisation d'arguments, fichiers et répertoires, fonctions, etc.

En tant qu'administrateur système, les shells font partie des opérations quotidiennes. Les shells offrent souvent plus d'options et de flexibilité qu'une interface utilisateur graphique (GUI). Les tâches répétitives quotidiennes peuvent facilement être automatisées par des scripts, ou les tâches peuvent être programmées pour s'exécuter à certains moments de la journée. Un shell offre un moyen pratique d'interagir avec le système et vous permet d'en faire plus en moins de temps. Il existe de nombreux shells différents, notamment Bash, zsh, tcsh et PowerShell.

Dans cet article de blog en deux parties, je partage certains des one-liners Bash que j'utilise pour accélérer mon travail et laisser plus de temps pour boire du café. Dans ce premier article, je couvrirai l'historique, les derniers arguments, l'utilisation des fichiers et des répertoires, la lecture du contenu des fichiers et les fonctions Bash. Dans la deuxième partie, j'examinerai les variables shell, la commande find, les descripteurs de fichiers et l'exécution d'opérations à distance.

Utilisez la commande d'historique

L'history la commande est pratique. History me permet de voir quelles commandes j'ai exécutées sur un système particulier ou quels arguments ont été passés à cette commande. J'utilise history pour relancer des commandes sans avoir à se souvenir de quoi que ce soit.

L'enregistrement des commandes récentes est stocké par défaut dans ~/.bash_history. Cet emplacement peut être modifié en modifiant la variable shell HISTFILE. Il existe d'autres variables, telles que HISTSIZE (lignes à stocker en mémoire pour la session en cours) et HISTFILESIZE (combien de lignes à conserver dans le fichier historique). Si vous voulez en savoir plus sur l'history , voir man bash .

Disons que j'exécute la commande suivante :

$> sudo systemctl status sshd

Bash me dit que le service sshd ne fonctionne pas, donc la prochaine chose que je veux faire est de démarrer le service. J'avais vérifié son statut avec ma commande précédente. Cette commande a été enregistrée dans history , afin que je puisse le référencer. Je lance simplement :

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

L'expression ci-dessus a le contenu suivant :

  •  !! - répéter la dernière commande de l'historique
  • :s/status/start/ - remplace status avec start

Le résultat est que le service sshd est démarré.

Ensuite, j'augmente la valeur par défaut de HISTSIZE de 500 à 5000 en utilisant la commande suivante :

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

Et si je veux afficher les trois dernières commandes de mon historique ? Je saisis :

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

Je lance tail sur audit.log en se référant au numéro de la ligne d'historique. Dans ce cas, j'utilise la ligne 1003 :

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

Imaginez que vous avez copié quelque chose depuis un autre terminal ou votre navigateur et que vous collez accidentellement la copie (que vous avez dans le tampon de copie) dans le terminal. Ces lignes seront stockées dans l'historique, ce que vous ne voulez pas. C'est donc là que unset HISTFILE &&exit est pratique

$> unset HISTFILE && exit

ou

$> kill -9 $$

Référence au dernier argument de la commande précédente

Lorsque je souhaite répertorier le contenu des répertoires de différents répertoires, je peux changer de répertoire assez souvent. Il existe une astuce intéressante que vous pouvez utiliser pour faire référence au dernier argument de la commande précédente. Par exemple :

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

Dans l'exemple ci-dessus, /some/very/long/path/to/some/directory est le dernier argument de la commande précédente.

Si je veux cd (changer de répertoire) à cet emplacement, je saisis quelque chose comme ceci :

$> cd $_

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

Maintenant, utilisez simplement un tiret pour revenir là où j'étais :

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

Travailler sur des fichiers et des répertoires

Imaginez que je veuille créer une structure de répertoires et déplacer un tas de fichiers ayant différentes extensions vers ces répertoires.

Tout d'abord, je crée les répertoires en une seule fois :

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

Ensuite, je déplace les fichiers en fonction de l'extension de fichier vers chaque répertoire :

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

Les caractères à double tiret -- signifie Fin des options. Cet indicateur empêche les fichiers commençant par un tiret d'être traités comme des arguments.

Ensuite, je veux remplacer/déplacer tous les fichiers *.txt vers des fichiers *.log, donc j'entre :

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

Au lieu d'utiliser le for boucle ci-dessus, je peux installer le prename commandez et accomplissez l'objectif ci-dessus comme ceci :

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

Souvent, lors de la modification d'un fichier de configuration, je fais une copie de sauvegarde de l'original en utilisant une commande de copie de base. Par exemple :

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

Comme vous pouvez le voir, répéter tout le chemin et ajouter .back au fichier n'est pas si efficace et probablement sujet aux erreurs. Il existe un moyen plus court et plus propre de le faire. Le voici :

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

Vous pouvez effectuer différentes vérifications sur des fichiers ou des variables. Exécutez le help test pour plus d'informations.

Utilisez la commande suivante pour découvrir si un fichier est un lien symbolique :

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

Voici un problème que j'ai rencontré récemment. Je voulais gunzip/untar un tas de fichiers en une seule fois. Sans réfléchir, j'ai tapé :

$> tar zxvf *.gz

Le résultat était :

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

Les fichiers tar étaient :

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

Pourquoi cela n'a-t-il pas fonctionné, et pourquoi ls -l *.gz travailler à la place ? Sous le capot, ça ressemble à ça :

$> tar zxvf *.gz

Se transforme comme suit :

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

Le tar La commande devrait trouver openvpn.tar.gz dans iptables.tar.gz. J'ai résolu ce problème avec un simple for boucle :

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

Je peux même générer des mots de passe aléatoires en utilisant Bash ! Voici un exemple :

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

Voici un exemple qui utilise OpenSSL :

$> openssl rand -base64 12
JdDcLJEAkbcZfDYQ

Lire un fichier ligne par ligne

Supposons que j'ai un fichier avec beaucoup d'adresses IP et que je souhaite opérer sur ces adresses IP. Par exemple, je veux exécuter dig pour récupérer les informations DNS inversées pour les adresses IP répertoriées dans le fichier. Je souhaite également ignorer les adresses IP qui commencent par un commentaire (# ou hashtag).

Je vais utiliser fileA comme exemple. Son contenu est :

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

Je pourrais copier et coller chaque adresse IP, puis exécuter dig manuellement :

$> dig +short -x 10.10.12.13

Ou je pourrais faire ceci :

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

Et si je veux échanger les colonnes dans le fichier A ? Par exemple, je veux mettre les adresses IP dans la colonne la plus à droite pour que le fichierA ressemble à ceci :

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

Je cours :

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

Utiliser les fonctions Bash

Les fonctions dans Bash sont différentes de celles écrites en Python, C, awk ou d'autres langages. Dans Bash, une fonction simple qui accepte un argument et affiche "Hello world" ressemblerait à ceci :

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

Je peux appeler la fonction comme ceci :

$> func foo

Parfois, une fonction s'invoque de manière récursive pour effectuer une certaine tâche. Par exemple :

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

Cette récursivité fonctionnera indéfiniment et utilisera beaucoup de ressources. Dans Bash, vous pouvez utiliser FUNCNEST pour limiter la récursivité. Dans l'exemple suivant, j'ai défini FUNCNEST=5 pour limiter la récursivité à cinq.

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)

Utiliser une fonction pour récupérer le fichier le plus récent ou le plus ancien

Voici un exemple de fonction pour afficher le fichier le plus récent dans un certain répertoire :

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

Cette fonction affiche le fichier le plus ancien d'un certain répertoire :

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

Ce ne sont là que quelques exemples de la façon d'utiliser les fonctions de Bash sans appeler d'autres commandes externes.

Je me retrouve parfois à taper une commande encore et encore avec beaucoup de paramètres. Une commande que j'utilise souvent est kubectl (CLI Kubernetes). J'en ai marre de lancer cette longue commande ! Voici la commande d'origine :

$> kubectl -n my_namespace get pods

ou

$> kubectl -n my_namespace get rc,services

Cette syntaxe m'oblige à inclure manuellement -n my_namespace chaque fois que j'exécute la commande. Il existe un moyen plus simple de le faire en utilisant une fonction :

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

Maintenant, je peux exécuter kubectl sans avoir à taper -n namespace à chaque fois :

$> kubectl get pods

Je peux appliquer la même technique à d'autres commandes.

Récapitulez

Ce ne sont là que quelques excellentes astuces qui existent pour Bash. Dans la deuxième partie, je montrerai quelques exemples supplémentaires, y compris l'utilisation de la recherche et de l'exécution à distance. Je vous encourage à pratiquer ces astuces pour rendre vos tâches d'administration en ligne de commande plus faciles et plus précises.

[ Cours en ligne gratuit :Présentation technique de Red Hat Enterprise Linux. ]


Linux
  1. Astuces Bash plus stupides :variables, recherche, descripteurs de fichiers et opérations à distance

  2. Trouvez les fichiers et répertoires les plus volumineux sous Linux

  3. Comment créer et appeler des fonctions dans Bash

  4. Linux Supprimer des fichiers et des répertoires

  5. Renommer les fichiers et répertoires de manière récursive sous ubuntu /bash

Comment compresser des fichiers et des répertoires sous Linux

Comment synchroniser des fichiers et des répertoires à l'aide de Zaloha.sh

Compresser et archiver des fichiers et des répertoires

Trouvez facilement des fichiers et des répertoires sur Linux

Fichiers et répertoires par défaut dans cPanel

Comment effacer l'historique de Bash sous Linux et Mac