web-dev-qa-db-fra.com

Comment rediriger stderr vers un fichier

Lors de l'utilisation de Nohup pour mettre une commande à exécuter en arrière-plan, certains contenus apparaissent dans le terminal.

cp: error reading ‘/mnt/tt/file.txt’: Input/output error
cp: failed to extend ‘/mnt/tt/file.txt’: Input/output error

Je veux enregistrer ce contenu dans un fichier.

269
André M. Faria

Il existe deux principaux flux de sortie sous Linux (et les autres systèmes d’exploitation), la sortie standard (stdout) et l’erreur standard (stderr). Les messages d'erreur, comme ceux que vous affichez, sont imprimés avec l'erreur standard. L'opérateur de redirection classique (command > file) ne redirige que la sortie standard. Par conséquent, l'erreur standard est toujours affichée sur le terminal. Pour rediriger stderr également, vous avez plusieurs choix:

  1. Rediriger stdout vers un fichier et stderr vers un autre fichier:

    command > out 2>error
    
  2. Transférez stderr vers stdout (&1), puis redirigez stdout vers un fichier:

    command >out 2>&1
    
  3. Redirige les deux vers un fichier (par exemple, ce n'est pas pris en charge par tous les shells, par exemple, bash et zsh, mais sh et ksh ne le supportent pas):

    command &> out
    

Pour plus d'informations sur les différents opérateurs de contrôle et de redirection, voir here .

469
terdon

La première chose à noter est qu'il y a plusieurs façons selon votre objectif et Shell. Par conséquent, cela nécessite une légère compréhension de plusieurs aspects. De plus, certaines commandes telles que time et strace écrivent une sortie sur stderr par défaut et peuvent ou non fournir une méthode de redirection spécifique à cette commande.

Selon la théorie de base de la redirection, un processus généré par Shell (en supposant qu'il s'agisse d'une commande externe et non de celle intégrée à Shell) est créé via fork() et execve() syscalls, et avant que cela se produise, un autre syscall dup2() effectue les redirections nécessaires avant que execve() ne se produise. En ce sens, les redirections sont héritées du shell parent. m&>n et m>n.txt informent le shell de la procédure à suivre pour exécuter open() et dup2() syscall (voir aussi Fonctionnement de la redirection d'entrée , Quelle est la différence entre redirection et pipe et Que signifie exactement dans la redirection de sortie )

Redirections shell

Le plus typique est via 2> dans shells Bourne-like , tel que dash (qui est lié symboliquement à /bin/sh) et bash; Le premier est le shell par défaut compatible avec POSIX et le second est celui que la plupart des utilisateurs utilisent pour les sessions interactives. Ils diffèrent par leur syntaxe et leurs fonctionnalités, mais heureusement pour nous, la redirection de flux d’erreur fonctionne de la même manière (à l’exception de la &> non standard). Dans le cas de csh et ses dérivés, la redirection stderr ne fonctionne pas très bien là.

Revenons à la partie 2>. Deux points essentiels à noter: > signifie opérateur de redirection, dans lequel nous ouvrons un fichier et 2 entier représente le descripteur de fichier stderr; En fait, c’est exactement comment le standard POSIX pour le langage Shell définit la redirection dans section 2.7 :

[n]redir-op Word

Pour une redirection > simple, le nombre entier 1 est impliqué pour stdout, c.-à-d. echo Hello World > /dev/null est identique à echo Hello World 1>/dev/null. Notez que l'opérateur entier ou l'opérateur de redirection ne peut pas être cité, sinon Shell ne les reconnaît pas comme tels et les considère plutôt comme une chaîne de texte littérale. En ce qui concerne l'espacement, il est important que l'entier se trouve juste à côté de l'opérateur de redirection, mais que le fichier peut l'être ou non de l'opérateur de redirection, c.-à-d. command 2>/dev/null et command 2> /dev/null fonctionneront très bien.

La syntaxe quelque peu simplifiée pour une commande typique dans Shell serait

 command [arg1] [arg2]  2> /dev/null

L'astuce ici est que la redirection peut apparaître n'importe où. C'est-à-dire que 2> command [arg1] et command 2> [arg1] sont valides. Notez que pour bash Shell, il existe &> moyen de rediriger les flux stdout et stderr en même temps, mais là encore - il est spécifique à bash et si vous recherchez la portabilité des scripts, cela risque de ne pas fonctionner. Voir aussi Wiki Ubunt et Quelle est la différence entre &> et 2> & 1 .

Remarque: L'opérateur de redirection > tronque un fichier et le remplace si le fichier existe. Le 2>> peut être utilisé pour ajouter stderr au fichier.

Si vous le remarquez, > est destiné à une seule commande. Pour les scripts, nous pouvons rediriger le flux stderr de l'intégralité du script depuis l'extérieur comme dans myscript.sh 2> /dev/null ou nous pouvons utiliser exec intégré . Le module d'exécution intégré a le pouvoir de recâbler le flux pour l'ensemble de la session Shell, pour ainsi dire, de manière interactive ou via un script. Quelque chose comme

#!/bin/sh
exec 2> ./my_log_file.txt
stat /etc/non_existing_file

Dans cet exemple, le fichier journal devrait indiquer stat: cannot stat '/etc/non_existing_file': No such file or directory.

Une autre méthode consiste à utiliser des fonctions. Comme kopciuszek indiqué dans sa réponse, nous pouvons écrire une déclaration de fonction avec une redirection déjà attachée, c'est-à-dire

some_function(){
    command1
    command2
} 2> my_log_file.txt

Commandes écrivant exclusivement sur stderr

Les commandes telles que time et strace écrivent leur sortie sur stderr par défaut. Dans le cas de la commande time, la seule alternative viable consiste à rediriger la sortie de la commande entière, c'est-à-dire

time echo foo 2>&1 > file.txt

sinon, liste synchrone ou sous-shell peuvent être redirigés si vous souhaitez séparer la sortie (comme indiqué dans related post ):

{ time sleep 1 2> sleep.stderr ; } 2> time.txt

D'autres commandes, telles que strace ou dialog, permettent de rediriger stderr. strace a l'option -o <filename.txt> qui permet de spécifier le nom du fichier dans lequel la sortie doit être écrite. Il existe également une option pour écrire un fichier texte pour chaque sous-processus visible par strace. La commande dialog écrit l'interface utilisateur textuelle sur stdout mais la sortie sur stderr, donc pour enregistrer sa sortie dans une variable (car var=$(...) et les pipelines ne reçoivent que stderr), nous devons échanger les descripteurs de fichier.

result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);

mais en plus, il y a le drapeau --output-fd, que nous pouvons également utiliser. Il y a aussi la méthode des tubes nommés. Je vous recommande de lire l'article lié sur la commande dialog pour une description détaillée de ce qui se passe.

14