web-dev-qa-db-fra.com

Est-il sûr de rediriger stdout et stderr vers le même fichier sans copie de descripteur de fichier?

Je commence dans un répertoire vide.

$ touch aFile
$ ls
aFile

Ensuite, je ls deux arguments, dont l'un n'est pas dans ce répertoire. Je redirige les deux flux de sortie vers un fichier nommé output. J'utilise >> afin d'éviter d'écrire simultanément.

$ ls aFile not_exist >>output 2>>output
$ cat output
ls: cannot access 'not_exist': No such file or directory
aFile

Ce qui semble fonctionner. Y a-t-il des dangers à cette approche?

27
exit_status

Non, ce n'est pas aussi sûr que le standard >>bar 2>&1.

Quand tu écris

foo >>bar 2>>bar

vous ouvrez le fichier bar deux fois avec O_APPEND, créant deux objets fichier complètement indépendants [1], chacun avec son propre état (pointeur, modes ouverts, etc.).

Ceci est très différent de 2>&1 Qui appelle simplement l'appel système dup(2) et crée les alias interchangeables stderr et stdout pour le même objet fichier.

Maintenant, il y a un problème avec ça:

O_APPEND Peut entraîner des fichiers corrompus sur les systèmes de fichiers NFS si plusieurs processus ajoutent des données à un fichier à la fois. Cela est dû au fait que NFS ne prend pas en charge l'ajout à un fichier, le noyau client doit donc le simuler, ce qui ne peut pas être fait sans condition de concurrence critique.

Vous pouvez généralement compter sur la probabilité que le fichier comme bar dans foo >>bar 2>&1 Soit écrit en même temps à partir de deux endroits distincts étant assez faible. Mais par votre >>bar 2>>bar Vous venez de l'augmenter d'une douzaine d'ordres de grandeur, sans aucune raison.

[1] "Open File Descriptions" dans le jargon POSIX.

22
mosvy

Que se passe-t-il lorsque vous le faites

some_command >>file 2>>file

est que file sera ouvert pour être ajouté deux fois. Ceci est sûr à faire sur un système de fichiers POSIX. Toute écriture qui arrive au fichier lorsqu'il est ouvert pour l'ajout se produira à la fin du fichier, que les données proviennent du flux de sortie standard ou du flux d'erreur standard.

Cela repose sur la prise en charge des opérations d'écriture d'ajout atomique dans le système de fichiers sous-jacent. Certains systèmes de fichiers, tels que NFS, ne prennent pas en charge l'ajout atomique. Voir par exemple la question "Le fichier est-il atomique sous UNIX?" sur StackOverflow.

En utilisant

some_command >>file 2>&1

fonctionnerait même sur NFS cependant.

Cependant, en utilisant

some_command >file 2>file

n'est pas sûr, car le shell tronquera le fichier de sortie (deux fois) et toute écriture qui se produira sur l'un ou l'autre flux ( écrasera les données déjà écrites par l'autre courant.

Exemple:

$ { echo hello; echo abc >&2; } >file 2>file
$ cat file
abc
o

La chaîne hello est écrite en premier (avec une nouvelle ligne de fin), puis la chaîne abc suivie d'une nouvelle ligne est écrite à partir de l'erreur standard, écrasant la hell. Le résultat est la chaîne abc avec une nouvelle ligne, suivie de ce qui reste de la première sortie echo, une o et une nouvelle ligne.

L'échange des deux echo autour de la plaie ne produit que hello dans le fichier de sortie car cette chaîne est écrite en dernier et est plus longue que la chaîne abc. L'ordre dans lequel les redirections se produisent n'a pas d'importance.

Il serait préférable et plus sûr d'utiliser le plus idiomatique

some_command >file 2>&1
22
Kusalananda

Cela dépend de ce que vous voulez réaliser. C'est à vous de décider si vous pouvez avoir des erreurs dans le même fichier que la sortie. Il s'agit simplement d'enregistrer du texte dans un fichier avec les fonctionnalités du Shell qui vous permettent de rediriger comme vous le souhaitez. Il n'y a pas de oui ou de non absolu. Comme tout sous Linux, cela peut se faire de plusieurs manières, c'est ma façon ls notExistingFile existingFile >> output 2>&1 Pour répondre à la question: en termes de redirection elle-même, oui, c'est parfaitement sûr.

0
Angel