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 errorcp: failed to extend ‘/mnt/tt/file.txt’: Input/output error

Je souhaite enregistrer ce contenu dans un fichier.

Il existe deux flux de sortie principaux sous Linux( et d'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 en erreur standard. L'opérateur de redirection classique (command > file) ne redirige que la sortie standard, donc l'erreur standard est toujours affichée sur le terminal. Pour rediriger également stderr, vous avez quelques choix:

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

    command > out 2>error
  2. Rediriger la sortie standard vers un fichier (>out), puis redirigez stderr vers stdout (2>&1):

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

    command &> out

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

La première chose à noter est qu'il y a deux façons en fonction de votre objectif et de votre shell, donc cela nécessite une légère compréhension de plusieurs aspects. De plus, certaines commandes telles que time et strace ecrire la sortie dans stderr par défaut, et peut ou non fournir une méthode de redirection spécifique à cette commande

La théorie de base derrière la redirection est qu'un processus généré par shell (en supposant qu'il s'agit d'une commande externe et non d'un shell intégré) est créé via fork() et execve() appels système, et avant que cela ne se produise un autre appel système dup2() effectue les redirections nécessaires avant execve() arriver. En ce sens, les redirections sont héritées du shell parent. Le m&>n et m>n.txt informez le shell sur la façon de procéder open() et dup2() syscall (voir aussi Comment fonctionne la redirection d'entrée, Quelle est la différence entre redirection et pipe, et Que signifie exactement & dans la redirection de sortie )

Redirections de Shell

Le plus typique, est via 2> dans Coquilles en forme de Bourne, notamment dash (qui est lié symboliquement à /bin/sh) et bash le premier est le shell par défaut et compatible POSIX et l'autre est ce que la plupart des utilisateurs utilisent pour une session interactive. Ils diffèrent par la syntaxe et les fonctionnalités, mais heureusement pour nous, la redirection de flux d'erreurs fonctionne de la même manière (sauf le &> non standard). Dans le cas de csh et de ses dérivés, la redirection stderr ça ne marche pas tout à fait là-bas.

Revenons à 2> partie. Deux choses clés à remarquer: > signifie opérateur de redirection, où nous ouvrons un fichier et 2 integer signifie descripteur de fichier stderr; en fait, c'est exactement ainsi que la norme POSIX pour le langage shell définit la redirection dans section 2.7:

[n]redir-op word

Pour simple > redirection, le 1 entier est implicite pour stdout, i.e. echo Hello World > /dev/null c'est exactement la même chose que echo Hello World 1>/dev/null. Notez que l'opérateur entier ou de redirection ne peut pas être entre guillemets, sinon le shell ne les reconnaît pas en tant que tels et les traite à la place comme une chaîne de texte littérale. En ce qui concerne l'espacement, il est important que integer soit juste à côté de l'opérateur de redirection, mais file peut être à côté de l'opérateur de redirection ou non, c'est-à-dire command 2>/dev/null et command 2> /dev/null fonctionnera très bien.

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

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

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

Note: Le > opérateur de redirection tronquer un fichier et l'écrase, si le fichier existe. Le 2>> peut être utilisé pour l'ajout stderr déposer.

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

#!/bin/shexec 2> ./my_log_file.txtstat /etc/non_existing_file

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

Encore une autre façon est via les fonctions. Comme Cendrillon noté dans sa réponse, nous pouvons écrire une déclaration de fonction avec une redirection déjà jointe, c'est-à-dire

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

Commandes écrivant exclusivement dans stderr

Commandes telles que time et strace écrivez leur sortie dans stderr par défaut. En cas de time commande, la seule alternative viable est de rediriger la sortie de la commande entière , c'est-à-dire

time echo foo 2>&1 > file.txt

alternativement, la liste synchrone ou le sous-shell peut être redirigé si vous souhaitez séparer la sortie ( comme indiqué dans article connexe ):

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

D'autres commandes, telles que strace ou dialog fournir des moyens de rediriger stderr. strace avoir -o <filename.txt> option qui permet de spécifier le nom du fichier où la sortie doit être écrite. Il existe également une option pour écrire un fichier texte pour chaque sous-processus qui strace voir. Le dialog la commande écrit l'interface utilisateur textuelle dans stdout mais la sortie dans stderr, afin de enregistrer sa sortie dans la variable ( parce var=$(...) et les pipelines ne reçoivent que stderr) nous devons échanger les descripteurs de fichiers

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

mais en plus, il y a --output-fd drapeau, que nous pouvons également utiliser. Il y a aussi la méthode des tuyaux nommés. Je recommande de lire le post lié sur le dialog commande pour une description complète de ce qui se passe.

@terdon C’est une question plus spécifique, et elle apparaît à juste titre dans la recherche Google pour la question plus spécifique, ce qui est une bonne chose.

@nroose oui, et il continuera à apparaître, cela ne changera pas. Mais toute nouvelle réponse devrait aller à la question plus générale.