Sur cet 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/null
sur quelque chose? Je ne comprends pas ce que l’on veut faire ici (est-ce comme utiliser while TRUE; sleep 1; elihw
pour {some busy program}
?). Pourtant, l'auteur appelle cela «Rien d'inhabituel».
En règle générale, cat /dev/null > [something]
vous permet d'effacer le contenu du fichier tout en vous assurant qu'il n'y a absolument aucun risque d'interruption de l'état du fichier. Le contenu du fichier sera clairement effacé par le cat /dev/null
mais le fichier 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. Ainsi, par exemple, un rm /var/log/messages && touch /var/log/messages
perturberait d'autres processus et pourrait provoquer l'étouffement des processus en cours. Cela signifie qu'un processus qui est verrouillé sur un numéro d'inode spécifique connecté au fichier /var/log/messages
pourrait 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/l'état d'un fichier, l'utilisation de cat /dev/null > [something]
est préférée par les administrateurs système qui souhaitent effacer un journal mais ne souhaitent pas potentiellement interférer avec le fonctionnement de processus déjà existants.
En outre, dans le contexte de la page vers laquelle vous créez un lien l'auteur indique 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 ressaisir encore et encore.
Donc, le «rien d’inhabituel» que l’auteur mentionne concerne tout le concept de ce script bash spécifique: c’est 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.
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. Un moyen 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, cat /dev/null > file
, atteint correctement l'objectif cependant, malgré une légende urbaine tenace, sa partie cat /dev/null
ne fait absolument rien d’utile. 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. Elle peut être remplacée sans aucune modification fonctionnelle par la commande no-op sans doute plus rapide :
ou même, avec la plupart des shells, par aucune commande.
Laissez-moi essayer une métaphore pour expliquer à quel point cat /dev/null
est 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 (> file
) fait, é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
name__). C'est l'étape inutile.
Si vous lisez votre document lié jusqu'à 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; Dommage que cat /dev/null
soit conservé dans le code.
Cela signifie que le code suivant fonctionnera avec tous les shells courants (familles csh
et sh
name__):
cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."
et cela fonctionnera avec tous les shells utilisant la syntaxe Bourne, comme ash
name__, bash
name__, ksh
name__, zsh
et les goûts suivants:
cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
Notez toutefois qu'avec les anciens shells Bourne pré-POSIX, aucune de ces commandes, y compris cat /dev/null
, ne tronquera un fichier s'il est écrit par la suite par un script Shell en cours d'exécution. 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 tels que wtmp
qui stocke des enregistrements de largeur fixe.
echo > file
echo "" > file
La suivante basée sur une option BSD sh
n'est pas portable, POSIX ne spécifie aucune option autorisée pour echo, vous pouvez donc vous retrouver avec un fichier contenant une ligne avec "-n
":
echo -n > file
Celui-ci n'est pas portable non plus à l'aide d'une séquence d'échappement sh
de 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, utiliser truncate
n'est pas portable car cette commande, qui n'est pas spécifiée par POSIX, est peut-être manquante sur 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 commande true
qui est strictement équivalente à la commande no-op one :
, même si elle est plus lisible:
true > file
C'est un moyen fastidieux de ramener le fichier à une taille nulle.
cd /var/log
> messages
> wtmp
echo "Log files cleaned up."