Pourquoi voudriez-vous "cat / dev / null> / var / log / messages"?

77

Sur cette page d'exemple de script bash, l'auteur présente ce script:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

Pourquoi voudriez-vous cat /dev/nullsur quelque chose? Je n'arrive pas à comprendre ce qui est prévu ici (est-ce que c'est comme utiliser while TRUE; sleep 1; elihwpour {some busy program}?). Pourtant, l'auteur appelle cela «Rien d'inhabituel».

isomorphismes
la source

Réponses:

40

Vous devez généralement cat /dev/null > [something]effacer le contenu du fichier tout en évitant tout risque d'interruption de l'état du fichier. Le contenu du fichier sera clairement effacé par le cat /dev/nullfichier lui-même - tel qu'il existe et est connu du système de fichiers sur lequel il réside - sera toujours là avec le même numéro d'inode, la même propriété et les mêmes autorisations.

Dans le cas d'un fichier journal, il se peut que le fichier journal lui-même soit marqué «en cours d'utilisation» par un autre processus. Ce faisant, par exemple, rm /var/log/messages && touch /var/log/messagescela pourrait perturber d'autres processus et provoquer l'étouffement des processus en cours. Signifier qu'un processus qui est en quelque sorte verrouillé sur un numéro d'inode spécifique connecté au fichier /var/log/messagespourrait soudainement paniquer en disant: «Hé! Qu'est-il arrivé à /var/log/messages! ”Même si le fichier est toujours là. Sans parler des problèmes potentiels avec la propriété et les autorisations étant recréées de manière incorrecte.

En raison de cette incertitude dans l' utilisation / état d'un fichier de l'utilisation cat /dev/null > [something]est préféré par les administrateurs système qui veulent effacer un journal , mais ne veulent pas potentiellement interférer avec le fonctionnement des processus déjà existants.

De même, dans le contexte de la page que vous créez un lien avec l'auteur, vous indiquez ce qui suit:

Il n’ya rien d’inhabituel ici, seul un ensemble de commandes qui auraient tout aussi bien pu être invoquées une à une à partir de la ligne de commande de la console ou d’une fenêtre de terminal. Les avantages de placer les commandes dans un script vont bien au-delà du fait de ne pas avoir à les retaper encore et encore.

Donc, le «rien d’inhabituel» que l’auteur mentionne concerne tout le concept de ce script bash spécifique: c’est juste un ensemble de commandes simples qui peuvent tout aussi bien être exécutées à partir de la ligne de commande mais placées dans un fichier texte évitez de les retaper encore et encore.

JakeGould
la source
10
@jlliagre La seule chose qui soit "maintenue en vie" est le contexte de la question qui est centrée sur les raisons pour lesquelles l'auteur d'origine ferait cela. Si vous êtes désireux de dissiper le "mythe", publiez une réponse fournissant un contexte à la méthode de codage de l'auteur original, ainsi qu'une perspective sur les raisons pour lesquelles vous pensez qu'il peut être remplacé par d'autres méthodes.
JakeGould
7
La réponse de @jlliagre Cyrus n'aborde pas la question fondamentale de savoir pourquoi l'auteur original aurait utilisé cette méthode ni le raisonnement qui la sous-tend. Le tutoriel mentionné est assez ancien et raisonnablement accepté. Ce n’est pas faux ni ne perpétue une prétendue "légende urbaine". C'est plutôt la façon dont une personne code par rapport à la manière dont une autre personne code. Aussi simple que cela. C'est une question de style qui n'a pas d'impact négatif sur la fiabilité ou la performance.
JakeGould
3
truncate -s 0ferait la même chose et serait moins idiomatique. Cependant, les programmeurs shell sont un groupe conservateur et on peut rencontrer des systèmes assez vieux ou assez farfelus pour ne pas avoir cette commande.
Schwern
5
@skift cat /dev/null > /foo/bartronque le fichier; echo "" > /foo/barle tronque puis écrit un seul caractère de nouvelle ligne.
David
2
Un autre avantage de cette méthode par rapport à rm & touch est que la propriété et les autorisations sont conservées.
jjmontes
121

Pourquoi voudriez-vous chat / dev / null sur quelque chose?

Vous ferez cela pour tronquer le contenu d'un fichier tout en conservant l'inode intact. Tous les programmes dont le fichier est ouvert en lecture ou en écriture ne seront pas affectés sauf que la taille du fichier sera remise à zéro.

Une alternative fausse souvent trouvée consiste à supprimer le fichier puis à le recréer:

rm file
touch file

ou similaire:

mv file file.old
gzip file.old
touch file

Le problème est que ces méthodes n’empêchent pas l’ancien fichier d’être conservé par tous les processus où le fichier supprimé est ouvert au moment de la suppression. La raison en est que, sous les systèmes de fichiers Unix, lorsque vous supprimez un fichier, vous ne faites que dissocier son nom (chemin) de son contenu (inode). L'inode est maintenu en vie tant qu'il existe des processus l'ayant ouvert en lecture ou en écriture.

Cela entraîne plusieurs effets négatifs: les journaux écrits après la suppression du fichier sont perdus car il n’existe aucun moyen simple / portable d’ouvrir un fichier supprimé. Tant qu'un processus écrit dans le fichier supprimé, son contenu utilise toujours de l'espace sur le système de fichiers. Cela signifie que si vous supprimez / créez le fichier parce qu'il remplissait votre disque, celui-ci reste rempli. Une façon de résoudre ce dernier problème consiste à redémarrer les processus du consignateur, mais vous pouvez ne pas le faire pour les services critiques et les journaux intermédiaires seraient définitivement perdus. Il existe également des effets secondaires dus au fait que le fichier que vous créez peut ne pas avoir les mêmes autorisations, propriétaire et groupe que celui d'origine. Cela pourrait, par exemple, empêcher un analyseur de journaux de lire le fichier nouvellement créé ou, pire, empêcher le processus de journalisation d'écrire ses propres journaux.

La première méthode permet d’ cat /dev/null > fileatteindre l’objectif correctement, mais malgré une légende urbaine tenace, sa cat /dev/nullpartie ne sert absolument à rien. Il ouvre un pseudo fichier qui est vide par conception, il ne lit rien et finit par se fermer. L'utilisation de cette commande est alors un gaspillage de frappes de touche, d'octets, d'appels système et de cycles de processeur et peut être remplacée sans aucune modification fonctionnelle par la commande no-op sans aucun doute plus rapide :ou même, avec la plupart des shells, par aucune commande.

Laissez-moi essayer une métaphore pour expliquer à quel point l'inutilité cat /dev/nullest inutile . Disons que votre objectif est de vider un verre.

  • Vous en retirez d'abord tout liquide. C'est suffisant et c'est précisément ce que fait ( > file) étant donné que les redirections sont toujours traitées en premier.

  • Ensuite, vous choisissez une bouteille vide ( /dev/null) et la versez dans le verre vide ( cat). C'est l'étape inutile

Si vous lisez votre document lié à la fin, vous remarquerez peut-être les commentaires dans cette ligne de la version améliorée du script:

    cat / dev / null> wtmp #   ':> wtmp' et '> wtmp' ont le même effet.

Ils ont en effet; tant pis a cat /dev/nullété conservé dans le code.

Cela signifie que le code suivant fonctionnera avec tous les shells courants (les deux cshet leurs shfamilles):

cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."

et cela fonctionnera avec toutes les coquilles en utilisant la syntaxe Bourne, comme ash, bash, ksh, zshet les goûts:

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

Notez cependant qu'avec les anciens shells Bourne pré-POSIX Bourne, aucune de ces commandes, y compris cat /dev/null, ne tronquera un fichier s'il est écrit ultérieurement par un script shell en cours d'exécution qui lui est ajouté. Au lieu d'un fichier de zéro octet, ce serait un fichier fragmenté dont la taille ne serait pas modifiée. La même chose se produirait si le fichier était écrit par un processus cherchant la position qu’il pensait être la précédente avant l’écriture.

Notez également que certaines solutions alternatives suggérées pour tronquer un fichier ont des défauts.

  • Les deux suivants ne font tout simplement pas le travail. Le fichier résultant n'est pas vide mais contient une ligne vide. Cela romprait les fichiers journaux comme wtmpceux stockant des enregistrements de largeur fixe.

    echo > file
    echo "" > file
  • La suivante basée sur une shoption BSD n'est pas portable, POSIX ne spécifie aucune option autorisée pour l'écho, vous pouvez donc vous retrouver avec un fichier contenant une ligne avec " -n":

    echo -n > file
  • Celui-ci n'est pas portable non plus en utilisant une shséquence d'échappement System V. Certains shells vont créer un fichier contenant une ligne avec " \c":

    echo "\c" > file
  • Celui-ci utilise une commande conçue pour faire le travail. Le problème n’est truncatepas portable car cette commande, qui n’a pas été spécifiée par POSIX, est peut-être absente d’un système Unix / Linux.

    truncate -s 0

Enfin, voici quelques solutions de rechange portables qui feront le travail correctement:

  • Imprimer explicitement une chaîne vide dans le fichier:

    printf "" > file
  • Utilisation de la truecommande strictement équivalente à la commande no-op :mais plus lisible:

    true > file
jlliagre
la source
1
@JonathanLeffler Je crois que cela fait partie de toutes les cshimplémentations actuelles bien que cela ne soit pas nécessairement documenté. À partir de la csh page de manuel Solaris : Null command. This command is interpreted, but performs no action.. Je n'ai trouvé aucune mention de la même chose dans la tcshpage de manuel ou dans les BSD d'origine csh, mais cette syntaxe a peut-être toujours fonctionné.
jlliagre
6
Une des raisons pour écrire cat /dev/nullest de rendre vos intentions explicites.
Davidmh
1
@ Davidmh Cela serait raisonnable, mais votre déclaration ne résiste pas à la vérification des faits. J'ai observé cet idiome de coquille pendant probablement plusieurs décennies. Lorsque j’ai eu l’occasion de demander à l’auteur de raisonner, j’ai toujours eu des théories douteuses sur l’utilisation /dev/nulld’un moyen efficace d’injecter zéro octet, de toute façon plus fiable que d’utiliser :ou rien. Dans cette même page, Cyrus répondait qu'il était concis, mais qu'il allait droit au but et qu'il ne comptait aucun vote alors que celui de JakeGould qui contestait le fait qu'il cat /dev/nullétait un non-op (voir nos commentaires) avait déjà au moins quatre votes.
Jlliagre
2
@ jlliagre ma connaissance de la coquille est assez basique, donc je ne suis peut-être pas la meilleure cible en termes de population; mais un nu >ou :n'est pas clair. Je conviens que c'est une honte que des mythes aient été propagés en raison de son utilisation.
Davidmh
4
@Davidmh Si vous voulez vraiment quelque chose d'explicite avant la redirection, je vous recommanderais à la printf "" > filefois portable (POSIX) et léger aussi souvent implémenté qu'un shell intégré.
Jlliagre
6

C'est un moyen fastidieux de ramener le fichier à une taille nulle.

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
Cyrus
la source
Cette syntaxe ne fonctionnera pas dans tous les shell.
reinierpost
2
Correct. La question est seulement taguée avec "bash".
Cyrus
@reinierpost Cela fonctionnera dans tous les coques à la Bourne, n'est-ce pas? Ne nous inquiétons pas csh.
Barmar
: > messagesfonctionne aussi. :ou truesont les choix les plus évidents pour les commandes qui n'impriment rien et qui retournent vrai.
Peter Cordes
-3

Pour tronquer un fichier ouvert. Ceci est équivalent et plus compréhensible:

echo -n > /var/log/messages

(Ajouté -n pour éviter la nouvelle ligne)

bbaassssiiee
la source
3
C'est en effet plus compréhensible mais malheureusement pas équivalent. Il va même casser des fonctionnalités comme dans le wtmpcas. Voir ma réponse mise à jour.
jlliagre
echo -n évite les sauts de ligne.
bbaassssiiee
6
En effet, si vous êtes sûr de l'utiliser bash, il -nn'est pas garanti qu'il fonctionne dans tous les coques Bourne.
Jlliagre