Difference between revisions of "HelloBash Ep2"
(→Redirection vers un fichier sans écraser le contenu existant : >|) |
|||
(One intermediate revision by the same user not shown) | |||
Line 115: | Line 115: | ||
> /tmp/foo | > /tmp/foo | ||
− | === Redirection vers un fichier sans écraser le contenu existant : > | + | === Redirection vers un fichier sans écraser le contenu existant : |> === |
Line 210: | Line 210: | ||
echo "test" >&3 | echo "test" >&3 | ||
cat /tmp/out | cat /tmp/out | ||
− | read -n 32 CONTENT <&4 | + | read -n 32 CONTENT <&4 |
− | + | echo $CONTENT | |
=== Fermeture d'un flux : N>&- N<&- === | === Fermeture d'un flux : N>&- N<&- === |
Latest revision as of 23:02, 26 March 2020
Contents
Un peu de théorie
Le shell que vous utilisez est probablement un stty
$ tty /dev/pts/0 $ whatis pts pts (4) - pseudoterminal master and slave $ stty speed 38400 baud; line = 0; -brkint -imaxbel
Un pts/stty est une «simulation de tty». TTY signifie TeleTYpe, qui est un descendant du télégraphe en usage dès les années 50.
Il est amusant de savoir que les teletypes communiquaient par modem via un réseau dédié, nommé teletype network, qui a donné le nom telnet
, un protocole défini dès la RFC 15, dont vous trouverez une analyse récente ici.
Pour une analyse poussée des tty et des teletype voir ici.
Un tty est un programme dont la fonctionnalité première est de gèrer du flux de texte.
Voilà ce que fait -un peu caricaturalement- un terminal comme à l'époque du teletype :
- Recevoir un text (input/STDIN) : création d'une chaîne de caractères individuels
- Analyser le texte saisi (parsing) : découpe de la chaîne de texte en commande + arguments
- Exécuter la commande avec ses arguments (exec[vlpe]) et retransmission des chaînes de sortie standard (output/STDOUT) et d'erreurs (errors/STDERR)
Ce qu'on appelle flux (ou streams) ce sont les différentes chaînes de caractères en transit : les STDIN, STDOUT, STDERR
Bash permet de manipuler ces flux. Force du shell : combiner des commandes existantes entre elles, via les flux.
Métaphore: un teletype qui enverrait un message en Italie, récupèrerait la sortie, remplacerait certains mots et retransmettrait le résultat en Allemagne.
Dans le cas d'un stty, pas besoin d'édition papier, tout se fait avec des chaînes de texte.
Les types de manipulation
Nous allons voir les manipulations de flux suivantes
- les redirections
- les pipes (pipelines/tubes)
Dans les deux cas nous verrons des commandes utiles associées à ces manipulations
Les redirections de flux
STDIN, STDOUT, STDERR
Un terminal est instancié avec 3 flux natifs numérotés 0, 1, et 2
$ ls -go /proc/self/fd total 0 lrwx------ 1 <...> 0 -> /dev/pts/4 lrwx------ 1 <...> 1 -> /dev/pts/4 lrwx------ 1 <...> 2 -> /dev/pts/4 lr-x------ 1 <...> 3 -> /proc/6017/fd $ ls -go /dev/STDIN lrwxrwxrwx 1 <...> /dev/STDIN -> /proc/self/fd/0
Ce sont des descripteurs de fichiers (file descriptors/fd) et ils peuvent être manipulés en les substituant avec d'autres descripteurs de fichiers.
Ils ont chacun un numéro standardisé :
- 0 == STDIN
- 1 == STDOUT
- 2 == STDERR
La redirection permet aux descripteurs de fichier des commandes d'être dupliqués, ouverts, fermés, de se référer à différents fichiers et de modifier les fichiers lus et écrits par la commande.
Les opérateurs de redirection peuvent précéder ou apparaître n'importe où dans une commande simple ou peuvent suivre une commande. Les redirections sont traitées dans l'ordre dans lequel elles apparaissent, de gauche à droite.
Les deux opération suivantes auront des résultats différents
commande redirection_1 redirection_2 commande redirection_2 redirection_1
Utilisation des flux standards pour les redirections
Les numéros de flux (0,1,2) sont utilisés pour rediriger les flux par défaut
Par défault, les opérateurs qui manipulent les flux input utilisent le numéro de fd 0 (STDIN).
Par défault, les opérateurs qui manipulent les flux output utilisent le numéro de fd 1 (STDOUT)
Pour signifier qu'on veut rediriger vers un flux existant, on le préfixe avec un "&", sinon Bash pense que vous parlez du fichier nommé "1", pas de /proc/self/fd/1.
Redirections de STDOUT et STDERR
Redirection simple : > et >>
Un simple > remplace un contenu existant vers une sortie existante ou créable
Un double >> concatène la sortie vers une sortie existante ou créable
ls > /tmp/list.txt ls >> /tmp/list.txt
Pour ces redirections, le stream "1" est la valeur par défaut quand on indique pas la source. Les deux exemples précédents équivalent à
ls 1>/tmp/list.txt ls 1>>/tmp/list.txt
On peut décider de créer un fichier avec les syntaxes suivantes, qui ne prennent aucune entrée
: > /tmp/foo > /tmp/foo
Redirection vers un fichier sans écraser le contenu existant : |>
Si on active le mode noclobber
de Bash, on ne peut modifier un fichier existant à moins d'utiliser cette syntaxe particulière
echo "ok" > /tmp/test set -o noclobber echo "bad" > /tmp/test echo "works" |> /tmp/test
Redirection de STDERR : 2>
Si on veut la sortie et les erreurs dans des fichiers différents
curl https://www.tmplab.org 1>/tmp/std 2>/tmp/err
Si on veut enregistrer à la fois les erreurs et la sortie dans un même fichier.
ls -lh /foo 1>/tmp/out 2>&1 cat /tmp/out
Attention, il faut bien rediriger d'abord la sortie sortie vers le fichier, sinon STDERR reste sur STDOUT
ls -lh /foo 2>&1 1>/tmp/out ls: impossible d'accéder à '/foo': Aucun fichier ou dossier de ce type
Redirection de STDERR et STDOUT : &>
On utilise cette syntaxe pour rediriger 1 et 2 vers un descripteur de fichier commun
ls -lh /proc/self/fd &>/tmp/out cat /tmp/out
On voit que 1 et 2 sont bien pointées vers /dev/null
Envoi de caractères dans STDERR : >&2
On peut rediriger une sortie vers un flux numéroté comme STDERR.
echo "Ooops" 1>&2
Redirections de STDIN
Redirection par un contenu de fichier : <
Cette syntaxe redirige par défaut le flux numéroté "0" vers le fichier indiqué
ls /proc/self/fd -lh </tmp/out
Elle peut être utile pour lancer une série de commandes SQL :
echo "show databases" > /tmp/query.sql mysql < /tmp/query.sql
Redirection par un document (Here Documents) : <<
Un Here Documents crée une entrée multiligne qui est passée en STDIN à la commande.
L'entrée est démarquée par la suite de caractères qui suit les caractères "<<". Elle se termine quand la suite de caractères est répétée sur une seule ligne avant un retour à la ligne, sans espaces.
cat << HEREDOC hello Bash It's great. We love it! HEREDOC
On peut créer des fichiers complexes en associant à un HEREDOC
cat 1>/tmp/out << SOMETHING my file is multiline! SOMETHING
Redirection par une chaîne (Here Strings) : <<<
Déclare une chaîne de caractères qui sera utilisé comme STDIN de la commande.
cat <<< "Hello Bash" bash <<< "sleep 1"
Création et fermeture de flux
Création de nouveaux flux : N< et N>
Cette syntaxe génère un flux numéroté "N" qui sera selon le sens du chevron un flux en entrée ou sortie.
En utilisant la commande exec
qui permet d'effectuer des redirections au sein du processus courant.
exec 3>/tmp/out exec 4</etc/passwd ls /proc/self/fd -lh echo "test" >&3 cat /tmp/out read -n 32 CONTENT <&4 echo $CONTENT
Fermeture d'un flux : N>&- N<&-
Cette commande supprime le flux numéroté "N" qu'on place avant le ">&-" ou "<&-".
Ce flux disparaît de la liste des descripteurs de fichiers du processus.
ls /proc/self/fd -lh exec 3<&- exec 4>&- ls /proc/self/fd -lh
Ouverture d'un flux pour entrée et sortie : N<>
Cette syntaxe permet de définir un flux numéroté N qui peut être utilisé à la fois pour lire et pour écrire.
echo 1234567890 > /tmp/file exec 3<> /tmp/file read -n 4 <&3 echo -n . >&3 exec 3>&- cat /tmp/file
Par exemple on peut appeler un flux TCP :
exec 3<>/dev/tcp/neverssl.com/80 echo -e "GET / HTTP/1.1\r\nhost: neverssl.com\r\nConnection: close\r\n\r\n" >&3 cat <&3
Ouverture d'un flux "anonyme" : <( command )
Cette syntaxe crée un type de descripteur de fichier particulier (un FIFO) qui contient le résultat de la commande appelée.
Par exemple, elle évite pour la commande suivante de stocker les résultats des commandes dans deux fichiers avant de les comparer.
diff -y <(man chattr) <(man chmod)
Les Pipes
Le pipe simple : |
Cette syntaxe permet de transmettre la STDOUT d'une commande comme STDIN d'une autre commande.
echo "hello" | ls -lh /proc/self/fd
On voit que le fd "0" est devenu un "pipe" : les données sont "versées" par la première commande dans la seconde.
Exemple. La première commande liste des fichiers. Cette liste est transmise à grep qui ne sélectionne que les lignes contenant un mot particulier
ls -lh /etc | grep shadow
Cette syntaxe toute simple ouvre beaucoup de possibilités. Quelques exemples.
ls -lh /etc | wc ls -lh /etc | head ls -lh /etc | tail ls -lh /etc | tr "aeiou" "_" ls -lh /etc |fmt -g 20 -s -
Les commandes comme fmt
acceptent souvent le caractère "-" pour signaler que les données à traiter sont fournies en input
On peut se retrouver à enchaîner les pipes.
cat *.txt | sort | uniq > result-file
Le pipe de redirection multi sorties : |&
Cette redirection renvoie à la fois STDOUT et STDERR dans le pipe
ls /foo |& cat >/tmp/out
Autre commandes
tee
Afficher sur l'écran la sortie standard et l'envoyer dans un fichier simultanément
echo "Do you want some tee?" | tee /tmp/out cat /tmp/out
Descripteurs de fichiers nommés
Ouvre un flux selon un nom de variable fourni.
Le contenu de la variable est le numéro du flux.
exec {myfd}> /tmp/out echo $myfd ls -lh /proc/self/fd echo "Noice" >&$myfd cat /tmp/out
Envoyer toute la sortie vers un fichier tout en l'affichant
Placée au début d'un programme cette ligne permet d'afficher la sortie des commandes tout en l'envoyant également vers un fichier
#!/bin/bash exec &> >(tee -a "$LOG_FILE") echo "This is 1" echo "This is 2" >&2
Intervertir STDERR et STDOUT
Cette ligne stocke STDOUT dans un flux numéroté "3", puis copie la cible de STDERR vers flux "1", avant de recopier STDIN vers le flux "2"
echo "hello bash" 3>&1 1>&2 2>&3 curl -v https://www.tmplab.org 1>/tmp/out 2>/tmp/err 3>&1 1>&2 2>&3
Récupérer les codes de sortie de commandes enchaînées avec des pipes
cmd1 | cmd2 | cmd3 | cmd4 echo ${PIPESTATUS[@]}
Sources
- https://catonmat.net/bash-one-liners-explained-part-three
- https://catonmat.net/ftp/bash-redirections-cheat-sheet.pdf
- https://xavcc.frama.io/introduction-stream/
- https://developer.ibm.com/tutorials/l-lpic1-103-2/
- https://developer.ibm.com/tutorials/l-lpic1-103-4/
- https://www.gnu.org/software/bash/manual/html_node/Redirections.html
- https://www.tldp.org/LDP/abs/html/io-redirection.html
- https://brennan.io/2015/01/16/write-a-shell-in-c/