Ce billet de blog est le deuxième de deux couvrant quelques trucs et astuces pratiques pour tirer le meilleur parti du shell Bash. Dans la première partie, j'ai couvert l'histoire, le dernier argument, le travail avec des fichiers et des répertoires, la lecture de fichiers et les fonctions Bash. Dans ce segment, je couvre les variables shell, la recherche, les descripteurs de fichiers et les opérations à distance.
Utiliser des variables shell
Les variables Bash sont définies par le shell lorsqu'elles sont appelées. Pourquoi devrais-je utiliser hostname
quand je peux utiliser $HOSTNAME, ou pourquoi devrais-je utiliser whoami
quand puis-je utiliser $USER ? Les variables bash sont très rapides et ne nécessitent pas d'applications externes.
Voici quelques variables fréquemment utilisées :
$PATH
$HOME
$USER
$HOSTNAME
$PS1
..
$PS4
Utilisez le echo
commande pour développer les variables. Par exemple, la variable shell $PATH peut être étendue en exécutant :
$> echo $PATH
[ Télécharger maintenant :Un guide de l'administrateur système sur les scripts Bash. ]
Utilisez la commande de recherche
Le find
La commande est probablement l'un des outils les plus utilisés dans le système d'exploitation Linux. Il est extrêmement utile dans les shells interactifs. Il est également utilisé dans les scripts. Avec find
Je peux répertorier les fichiers plus anciens ou plus récents qu'une date spécifique, les supprimer en fonction de cette date, modifier les autorisations des fichiers ou des répertoires, etc.
Familiarisons-nous avec cette commande.
Pour lister les fichiers de plus de 30 jours, je lance simplement :
$> find /tmp -type f -mtime +30
Pour supprimer des fichiers de plus de 30 jours, exécutez :
$> find /tmp -type f -mtime +30 -exec rm -rf {} \;
ou
$> find /tmp -type f -mtime +30 -exec rm -rf {} +
Bien que les commandes ci-dessus suppriment les fichiers de plus de 30 jours, telles qu'elles sont écrites, elles fork le rm
commande chaque fois qu'ils trouvent un fichier. Cette recherche peut être écrite plus efficacement en utilisant xargs
:
$> find /tmp -name '*.tmp' -exec printf '%s\0' {} \; | xargs -0 rm
Je peux utiliser find
pour lister sha256sum
fichiers uniquement en exécutant :
$> find . -type f -exec sha256sum {} +
Et maintenant, pour rechercher et supprimer les fichiers .jpg en double :
$> find . -type f -name '*.jpg' -exec sha256sum {} + | sort -uk1,1
Descripteurs de fichiers de référence
Dans le shell Bash, les descripteurs de fichiers (FD) sont importants pour gérer l'entrée et la sortie des commandes. De nombreuses personnes ont des problèmes pour comprendre correctement les descripteurs de fichiers. Chaque processus a trois descripteurs de fichier par défaut, à savoir :
Code | Signification | Emplacement | Description |
---|---|---|---|
0 | Saisie standard | /dev/stdin | Clavier, fichier ou un flux |
1 | Sortie standard | /dev/stdout | Moniteur, terminal, affichage |
2 | Erreur type | /dev/stderr | Les codes de sortie non nuls sont généralement>FD2, display |
Maintenant que vous savez ce que font les FD par défaut, voyons-les en action. Je commence par créer un répertoire nommé foo
, qui contient file1
.
$> ls foo/ bar/
ls: cannot access 'bar/': No such file or directory
foo/:
file1
La sortie Aucun fichier ou répertoire de ce type passe à l'erreur standard (stderr) et s'affiche également à l'écran. Je vais exécuter la même commande, mais cette fois, utilisez 2>
pour omettre stderr :
$> ls foo/ bar/ 2>/dev/null
foo/:
file1
Il est possible d'envoyer la sortie de foo
à la sortie standard (stdout) et à un fichier simultanément, et ignorez stderr. Par exemple :
$> { ls foo bar | tee -a ls_out_file ;} 2>/dev/null
foo:
file1
Ensuite :
$> cat ls_out_file
foo:
file1
La commande suivante envoie stdout à un fichier et stderr à /dev/null
afin que l'erreur ne s'affiche pas à l'écran :
$> ls foo/ bar/ >to_stdout 2>/dev/null
$> cat to_stdout
foo/:
file1
La commande suivante envoie stdout et stderr au même fichier :
$> ls foo/ bar/ >mixed_output 2>&1
$> cat mixed_output
ls: cannot access 'bar/': No such file or directory
foo/:
file1
C'est ce qui s'est passé dans le dernier exemple, où stdout et stderr ont été redirigés vers le même fichier :
ls foo/ bar/ >mixed_output 2>&1
| |
| Redirect stderr to where stdout is sent
|
stdout is sent to mixed_output
Une autre petite astuce (> Bash 4.4) pour envoyer à la fois stdout et stderr dans le même fichier utilise le signe esperluette. Par exemple :
$> ls foo/ bar/ &>mixed_output
Voici une redirection plus complexe :
exec 3>&1 >write_to_file; echo "Hello World"; exec 1>&3 3>&-
Voici ce qui se passe :
- exec 3>&1 Copier stdout dans le descripteur de fichier 3
- > write_to_file Faites FD 1 pour écrire dans le fichier
- echo "Hello World" Aller au fichier car FD 1 pointe maintenant vers le fichier
- exec 1>&3 Copier FD 3 vers 1 (swap)
- Trois>&- Fermer le descripteur de fichier trois (nous n'en avons plus besoin)
Il est souvent pratique de regrouper les commandes, puis d'envoyer la sortie standard vers un seul fichier. Par exemple :
$> { ls non_existing_dir; non_existing_command; echo "Hello world"; } 2> to_stderr
Hello world
Comme vous pouvez le voir, seul "Hello world" est imprimé à l'écran, mais la sortie des commandes ayant échoué est écrite dans le fichier to_stderr.
Exécuter des opérations à distance
J'utilise Telnet, netcat, Nmap et d'autres outils pour tester si un service distant est opérationnel et si je peux m'y connecter. Ces outils sont pratiques, mais ils ne sont pas installés par défaut sur tous les systèmes.
Heureusement, il existe un moyen simple de tester une connexion sans utiliser d'outils externes. Pour voir si un serveur distant exécute un site Web, une base de données, SSH ou tout autre service, exécutez :
$> timeout 3 bash -c ‘</dev/tcp/remote_server/remote_port’ || echo “Failed to connect”
Par exemple, pour voir si serveurA exécute le service MariaDB :
$> timeout 3 bash -c ‘</dev/tcp/serverA/3306’ || echo “Failed to connect”
Si la connexion échoue, le message Échec de la connexion message s'affiche sur votre écran.
Supposons que serveurA est derrière un pare-feu/NAT. Je veux voir si le pare-feu est configuré pour autoriser une connexion de base de données à serveurA , mais je n'ai pas encore installé de serveur de base de données. Pour émuler un port de base de données (ou tout autre port), je peux utiliser ce qui suit :
[serverA ~]# nc -l 3306
Sur clientA , exécutez :
[clientA ~]# timeout 3 bash -c ‘</dev/tcp/serverA/3306’ || echo “Failed”
Pendant que je parle de connexions à distance, qu'en est-il de l'exécution de commandes sur un serveur distant via SSH ? Je peux utiliser la commande suivante :
$> ssh remotehost <<EOF # Press the Enter key here
> ls /etc
EOF
Cette commande exécute ls /etc
sur l'hôte distant.
Je peux également exécuter un script local sur l'hôte distant sans avoir à copier le script sur le serveur distant. Une façon est d'entrer :
$> ssh remote_host 'bash -s' < local_script
Un autre exemple consiste à transmettre localement des variables d'environnement au serveur distant et à mettre fin à la session après l'exécution.
$> exec ssh remote_host ARG1=FOO ARG2=BAR 'bash -s' <<'EOF'
> printf %s\\n "$ARG1" "$ARG2"
> EOF
Password:
FOO
BAR
Connection to remote_host closed.
Il existe de nombreuses autres actions complexes que je peux effectuer sur l'hôte distant.
Récapitulez
Il y a certainement plus à Bash que ce que j'ai pu couvrir dans ce billet de blog en deux parties. Je partage ce que je sais et ce que je vis au quotidien. L'idée est de vous familiariser avec quelques techniques qui pourraient rendre votre travail moins sujet aux erreurs et plus amusant.
[ Vous voulez tester vos compétences d'administrateur système ? Faites une évaluation des compétences aujourd'hui. ]