Bash
Redirection
Recherche…
Syntaxe
- commande </ path / to / file # Redirection de l'entrée standard dans le fichier
- command> / path / to / file # Redirige la sortie standard vers flie
- commande descripteur_fichier> / chemin / vers / fichier # Redirige la sortie de descripteur_fichier vers le fichier
- commande> & file_descriptor # Redirige la sortie vers file_descriptor
- commande file_descriptor> & another_file_descriptor # Redirige file_descriptor vers another_file_descriptor
- commande <& file_descriptor # Redirige file_descriptor vers l'entrée standard
- commande &> / path / to / file # Redirige la sortie standard et l'erreur standard vers le fichier
Paramètres
Paramètre | Détails |
---|---|
descripteur de fichier interne | Un nombre entier. |
direction | Un de > , < ou <> |
descripteur de fichier externe ou chemin d'accès | & suivi d'un entier pour le descripteur de fichier ou un chemin. |
Remarques
Les programmes de la console UNIX ont un fichier d'entrée et deux fichiers de sortie (les flux d'entrée et de sortie, ainsi que les périphériques, sont traités comme des fichiers par le système d'exploitation). pour venir - ou aller à - un fichier ou un autre programme.
STDIN
est une entrée standard et est la manière dont le programme reçoit une saisie interactive. STDIN
est généralement STDIN
descripteur de fichier 0.
STDOUT
est une sortie standard. Tout ce qui est émis sur STDOUT
est considéré comme le "résultat" du programme. STDOUT
est généralement associé au descripteur de fichier 1.
STDERR
est l'endroit où les messages d'erreur sont affichés. En règle générale, lors de l'exécution d'un programme à partir de la console, STDERR
est STDERR
à l'écran et ne peut pas être distingué de STDOUT
. STDERR
est généralement associé au descripteur de fichier 2.
L'ordre de redirection est important
command > file 2>&1
Redirige les deux ( STDOUT
et STDERR
) vers le fichier.
command 2>&1 > file
Seulement redirections STDOUT
, parce que le descripteur de fichier 2 est redirigé vers le fichier pointé par le descripteur de fichier 1 ( ce qui est le fichier file
encore lorsque l'instruction est évaluée).
Chaque commande dans un pipeline a ses propres STDERR
(et STDOUT
) car chacun est un nouveau processus. Cela peut créer des résultats surprenants si vous vous attendez à ce qu'une redirection affecte l'ensemble du pipeline. Par exemple cette commande (enveloppée pour la lisibilité):
$ python -c 'import sys;print >> sys.stderr, "Python error!"' \
| cut -f1 2>> error.log
va imprimer "erreur Python!" à la console plutôt que le fichier journal. Au lieu de cela, attachez l'erreur à la commande que vous souhaitez capturer:
$ python -c 'import sys;print >> sys.stderr, "Python error!"' 2>> error.log \
| cut -f1
Redirection de la sortie standard
>
redirige la sortie standard (aka STDOUT
) de la commande en cours dans un fichier ou un autre descripteur.
Ces exemples écrivent la sortie de la commande ls
dans le fichier file.txt
ls >file.txt
> file.txt ls
Le fichier cible est créé s'il n'existe pas, sinon ce fichier est tronqué.
Le descripteur de redirection par défaut est la sortie standard ou 1
si aucun n'est spécifié. Cette commande est équivalente aux exemples précédents avec la sortie standard explicitement indiquée:
ls 1>file.txt
Remarque: la redirection est initialisée par le shell exécuté et non par la commande exécutée, elle est donc effectuée avant l'exécution de la commande.
Redirection de STDIN
<
lit à partir de son argument correct et écrit dans son argument de gauche.
Pour écrire un fichier dans STDIN
il faut lire /tmp/a_file
et écrire dans STDIN
c'est-à-dire 0</tmp/a_file
Remarque: le descripteur de fichier interne est STDIN
par défaut sur 0
( STDIN
) pour <
$ echo "b" > /tmp/list.txt
$ echo "a" >> /tmp/list.txt
$ echo "c" >> /tmp/list.txt
$ sort < /tmp/list.txt
a
b
c
Redirection à la fois STDOUT et STDERR
Les descripteurs de fichiers tels que 0
et 1
sont des pointeurs. Nous changeons ce que les descripteurs de fichiers indiquent avec la redirection. >/dev/null
signifie que 1
pointe vers /dev/null
.
D'abord, nous STDOUT
1
( STDOUT
) sur /dev/null
puis le point 2
( STDERR
) sur tout ce que 1
pointe vers.
# STDERR is redirect to STDOUT: redirected to /dev/null,
# effectually redirecting both STDERR and STDOUT to /dev/null
echo 'hello' > /dev/null 2>&1
Cela peut être réduit à ce qui suit:
echo 'hello' &> /dev/null
Toutefois, cette forme peut être indésirable en production si la compatibilité du shell est un problème car elle entre en conflit avec POSIX, introduit une ambiguïté d’analyse et que les shells sans cette fonctionnalité l’interprètent de manière erronée:
# Actual code
echo 'hello' &> /dev/null
echo 'hello' &> /dev/null 'goodbye'
# Desired behavior
echo 'hello' > /dev/null 2>&1
echo 'hello' 'goodbye' > /dev/null 2>&1
# Actual behavior
echo 'hello' &
echo 'hello' & goodbye > /dev/null
REMARQUE: &>
est connu pour fonctionner comme souhaité dans Bash et Zsh.
Redirection de STDERR
2
est STDERR
.
$ echo_to_stderr 2>/dev/null # echos nothing
Définitions:
echo_to_stderr
est une commande qui écrit "stderr"
dans STDERR
echo_to_stderr () {
echo stderr >&2
}
$ echo_to_stderr
stderr
Ajouter vs tronquer
Tronquer >
- Créez le fichier spécifié s'il n'existe pas.
- Tronquer (supprimer le contenu du fichier)
- Ecrire dans un fichier
$ echo "first line" > /tmp/lines
$ echo "second line" > /tmp/lines
$ cat /tmp/lines
second line
Ajouter >>
- Créez le fichier spécifié s'il n'existe pas.
- Ajouter un fichier (écriture à la fin du fichier).
# Overwrite existing file
$ echo "first line" > /tmp/lines
# Append a second line
$ echo "second line" >> /tmp/lines
$ cat /tmp/lines
first line
second line
STDIN, STDOUT et STDERR expliqués
Les commandes ont une entrée (STDIN) et deux types de sorties, la sortie standard (STDOUT) et l’erreur standard (STDERR).
Par exemple:
STDIN
root@server~# read
Type some text here
L'entrée standard est utilisée pour fournir une entrée à un programme. (Ici, nous utilisons la read
intégrée pour lire une ligne de STDIN.)
STDOUT
root@server~# ls file
file
La sortie standard est généralement utilisée pour une sortie "normale" à partir d'une commande. Par exemple, ls
répertorie les fichiers, de sorte que les fichiers sont envoyés à STDOUT.
STDERR
root@server~# ls anotherfile
ls: cannot access 'anotherfile': No such file or directory
L'erreur standard est (comme son nom l'indique) utilisée pour les messages d'erreur. Ce message n'étant pas une liste de fichiers, il est envoyé à STDERR.
STDIN, STDOUT et STDERR sont les trois flux standard. Ils sont identifiés à la coquille par un nombre plutôt que par un nom:
0 = standard dans
1 = Sortie standard
2 = erreur standard
Par défaut, STDIN est attaché au clavier et STDOUT et STDERR apparaissent dans le terminal. Cependant, nous pouvons rediriger STDOUT ou STDERR à tout ce dont nous avons besoin. Par exemple, supposons que vous ayez uniquement besoin de la sortie standard et que tous les messages d'erreur imprimés sur une erreur standard soient supprimés. C'est à ce moment que nous utilisons les descripteurs 1
et 2
.
Redirection de STDERR vers / dev / null
Prenant l'exemple précédent,
root@server~# ls anotherfile 2>/dev/null
root@server~#
Dans ce cas, s'il y a un STDERR, il sera redirigé vers / dev / null (un fichier spécial qui ignore tout ce qui y est placé), vous n'aurez donc aucune erreur sur le shell.
Redirection de plusieurs commandes vers le même fichier
{
echo "contents of home directory"
ls ~
} > output.txt
Utiliser des canaux nommés
Parfois, vous voudrez peut-être sortir quelque chose par un programme et l’entrer dans un autre programme, mais vous ne pouvez pas utiliser un canal standard.
ls -l | grep ".log"
Vous pouvez simplement écrire dans un fichier temporaire:
touch tempFile.txt
ls -l > tempFile.txt
grep ".log" < tempFile.txt
Cela fonctionne très bien pour la plupart des applications, cependant, personne ne saura ce tempFile
fait tempFile
et quelqu'un pourrait le supprimer s'il contient la sortie de ls -l
dans ce répertoire. C'est là qu'entre en jeu un tube nommé:
mkfifo myPipe
ls -l > myPipe
grep ".log" < myPipe
myPipe
est techniquement un fichier (tout est sous Linux), faisons donc ls -l
dans un répertoire vide que nous venons de créer dans un tube:
mkdir pipeFolder
cd pipeFolder
mkfifo myPipe
ls -l
La sortie est la suivante:
prw-r--r-- 1 root root 0 Jul 25 11:20 myPipe
Notez le premier caractère dans les autorisations, il est répertorié comme un tube, pas un fichier.
Maintenant, faisons quelque chose de cool.
Ouvrez un terminal et notez le répertoire (ou créez-en un pour faciliter le nettoyage) et créez un canal.
mkfifo myPipe
Maintenant, mettons quelque chose dans le tuyau.
echo "Hello from the other side" > myPipe
Vous remarquerez que cela se bloque, l'autre côté du tuyau est toujours fermé. Ouvrons l'autre côté du tuyau et passons à travers.
Ouvrez un autre terminal et accédez au répertoire dans lequel se trouve le tube (ou, si vous le connaissez, ajoutez-le au tube):
cat < myPipe
Vous remarquerez qu'après la sortie de hello from the other side
, le programme du premier terminal se termine, de même que celui du deuxième terminal.
Maintenant, lancez les commandes en sens inverse. Commencez avec le cat < myPipe
, puis cat < myPipe
écho à quelque chose. Cela fonctionne toujours, car un programme attendra que quelque chose soit mis dans le tube avant de se terminer, car il sait qu'il doit obtenir quelque chose.
Les canaux nommés peuvent être utiles pour déplacer des informations entre terminaux ou entre programmes.
Les pipes sont petites. Une fois rempli, le graveur se bloque jusqu'à ce qu'un lecteur lise le contenu. Vous devez donc exécuter le lecteur et le graveur sur différents terminaux ou exécuter l'un ou l'autre en arrière-plan:
ls -l /tmp > myPipe &
cat < myPipe
Plus d'exemples utilisant des canaux nommés:
Exemple 1 - Toutes les commandes sur le même terminal / même shell
$ { ls -l && cat file3; } >mypipe & $ cat <mypipe # Output: Prints ls -l data and then prints file3 contents on screen
Exemple 2 - Toutes les commandes sur le même terminal / même shell
$ ls -l >mypipe & $ cat file3 >mypipe & $ cat <mypipe #Output: This prints on screen the contents of mypipe.
file3
vous que le premier contenu defile3
est affiché, puis les donnéesls -l
sont affichées (configuration LIFO).Exemple 3 - Toutes les commandes sur le même terminal / même shell
$ { pipedata=$(<mypipe) && echo "$pipedata"; } & $ ls >mypipe # Output: Prints the output of ls directly on screen
$pipedata
vous que la variable$pipedata
n'est pas utilisable dans le terminal principal / shell principal car l'utilisation de&
invoque un sous-shell et que$pipedata
n'est disponible que dans ce sous-shell.Exemple 4 - Toutes les commandes sur le même terminal / même shell
$ export pipedata $ pipedata=$(<mypipe) & $ ls -l *.sh >mypipe $ echo "$pipedata" #Output : Prints correctly the contents of mypipe
Cela imprime correctement la valeur de la variable
$pipedata
dans le shell principal en raison de la déclaration d'exportation de la variable. Le terminal principal / shell principal n'est pas bloqué en raison de l'invocation d'un shell d'arrière-plan (&
).
Imprimer les messages d'erreur sur stderr
Les messages d'erreur sont généralement inclus dans un script à des fins de débogage ou pour fournir une expérience utilisateur enrichie. Il suffit d'écrire un message d'erreur comme ceci:
cmd || echo 'cmd failed'
peut fonctionner pour des cas simples mais ce n'est pas la manière habituelle. Dans cet exemple, le message d'erreur pollue la sortie réelle du script en mélangeant les erreurs et la sortie réussie dans stdout
.
En bref, le message d'erreur devrait aller à stderr
pas stdout
. C'est assez simple:
cmd || echo 'cmd failed' >/dev/stderr
Un autre exemple:
if cmd; then
echo 'success'
else
echo 'cmd failed' >/dev/stderr
fi
Dans l'exemple ci-dessus, le message de réussite sera imprimé sur stdout
tandis que le message d'erreur sera imprimé sur stderr
.
Une meilleure façon d’imprimer un message d’erreur est de définir une fonction:
err(){
echo "E: $*" >>/dev/stderr
}
Maintenant, quand vous devez imprimer une erreur:
err "My error message"
Redirection vers les adresses réseau
Bash considère certains chemins comme spéciaux et peut communiquer avec le réseau en écrivant dans /dev/{udp|tcp}/host/port
. Bash ne peut pas configurer un serveur d'écoute, mais peut initier une connexion, et pour TCP, il peut au moins lire les résultats.
Par exemple, pour envoyer une simple requête Web, vous pouvez:
exec 3</dev/tcp/www.google.com/80
printf 'GET / HTTP/1.0\r\n\r\n' >&3
cat <&3
et les résultats de la page Web par défaut de www.google.com
seront imprimés sur stdout
.
De même
printf 'HI\n' >/dev/udp/192.168.1.1/6666
enverrait un message UDP contenant HI\n
à un auditeur sur 192.168.1.1:6666