web-dev-qa-db-fra.com

Que fait:> filename.txt?

:>filename.txt

Par exemple:

root@box$ dd if=/dev/zero of=file.txt count=1024 bs=1024
1024+0 records in
1024+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00536175 s, 196 MB/s
root@box$ ll
total 1024
-rw-r--r-- 1 root root 1048576 Nov 15 14:40 file.txt
root@box$ :>file.txt
root@box$ ll
total 0
-rw-r--r-- 1 root root 0 Nov 15 14:40 file.txt

Est-ce différent d'un rm? Fonctionne-t-il plus rapidement ou plus lentement que d'autres moyens similaires de mise à zéro ou de suppression d'un fichier?

23
Kahn

Comme vous l'avez découvert, cela vide simplement le contenu du fichier (il tronque le fichier); qui est différent de rm car rm supprimerait réellement le fichier. Aditionellement, :>file.txt va réellement créer le fichier s'il n'existait pas déjà.

: est une "commande de ne rien faire" qui se terminera avec succès et ne produira aucune sortie, il s'agit donc simplement d'une méthode courte pour vider un fichier. Dans la plupart des shells, vous pouvez simplement faire >file.txt pour obtenir le même résultat. Il pourrait également être légèrement plus rapide que d'autres méthodes telles que echo >file.txt as echo pourrait potentiellement être une commande externe.

Aditionellement, echo >file.txt mettrait une ligne vide dans file.txt:>file.txt rendrait le fichier sans aucun contenu.

38
jesse_b

Oui, c'est différent de rm.

rm supprimerait le fichier.

:>filename.txt vide le fichier, le laissant toujours là, mais sans octets.

8
steve

L'invocation Shell de >filename.txt Redirige une sortie vers le fichier "filename.txt" pour le remplacer complètement. Ainsi, le Shell doit effacer tout le contenu du fichier donné avant d'y écrire la sortie.

La sortie à rediriger est la sortie de la commande exécutée. Comme:

$ echo Hello >filename.txt

Fera le fichier de nom filename.txt pour contenir exactement (et seulement) la chaîne Hello.

Exécution:

$ echo "New Value" >filename.txt
$ cat filename.txt
New Value

effacera tout ce qui se trouve dans le fichier, puis y inscrira New Value.

Si la commande n'a pas de sortie, comme la commande true, le fichier restera vide (tronqué).

$ true >filename.txt
$ cat filename.txt

Une commande qui est également un shell intégré est : (Juste un double point (deux points)) et qui n'a pas de sortie. Le fait d'être intégré le rend plus rapide qu'une commande externe telle que true (qui n'a pas non plus de sortie). Donc, soit:

$ :  >  filename.txt
$ :  >filename.txt
$ :>filename.txt

supprimera tout le contenu du fichier nommé filename.txt ou le créera en tant que fichier vide s'il n'existe pas.

Est-ce différent d'un RM?

C'est différent d'un rm, car un rm fera disparaître le fichier de ls, pas que le fichier contienne 0 octet.

Fonctionne-t-il plus rapidement ou plus lentement que d'autres moyens similaires de mise à zéro ou de suppression d'un fichier?

Encore une fois, le fichier n'est pas supprimé (disparaître de la liste donnée par ls) il se transforme en fichier vide (contient 0 octet).

Cela devrait être plus rapide que d'appeler une commande externe pour vider un fichier. Le fait d'avoir à créer un shell enfant pour charger l'exécutable et exec la commande rend les commandes externes plus lentes que la commande intégrée :.

Des solutions similaires sont (certaines définissent $? Sur 1):

[ ]         > filename.txt
builtin     > filename.txt
command     > filename.txt
printf ''   > filename.txt
4
Isaac

re: performance: c'est à peu près aussi efficace que possible dans le Shell; simplement demander au noyau de tronquer un fichier existant devrait être plus efficace que de dissocier le fichier et de recréer un nouvel inode avec le même nom. Sauf si vous voulez le fichier supprimé, auquel cas rm ou unlink it.

: Est un shell intégré, il évite donc fork/exec. Il en va de même de l'équivalent true dans les coquilles modernes normales.

>foo Ou true > foo Obtient le Shell pour tronquer le fichier en faisant un
open(path, O_WRONLY|O_TRUNC|O_CREAT, 0666) appel système.

Ou en pratique avec DASH sous Linux, à partir de la sortie strace sh:
openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3 qui est équivalent.

Ensuite, il doit close() que FD à nouveau. En fait, DASH ne présente pas de cas particulier lorsque vous utilisez :>, Il passe à travers les cercles suivants:

openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10          # save original stdout
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1           # redirect stdout to foo
close(3)                                = 0           # then close 3
dup2(10, 1)                             = 1           # then restore original stdout
fcntl(10, F_GETFD)                      = 0x1 (flags FD_CLOEXEC)
close(10)                               = 0

L'utilisation de > foo Dans DASH conduit à la même séquence d'appels système, redirigeant réellement fd1 puis le restaurant. Je n'ai pas vérifié bash ou d'autres shells.

Mais c'est encore beaucoup moins cher que de créer un nouveau processus pour exécuter truncate -s 0 foo Qui ferait (espérons-le) un seul truncate("foo", 0) appel système qui serait probablement encore plus efficace que un open + close.

À partir d'un langage comme C (ou n'importe quoi avec des liaisons d'appels système), tronquer un fichier que vous ne voulez pas ouvrir peut être fait plus efficacement avec un appel direct truncate.

Dans Dash, 3>foo Conduit à cette séquence d'appels système:

openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
close(3)                                = 0

L'ouverture d'un nouveau fd se traduit déjà par un fd 3, évitant tout duper. C'est le moyen le plus efficace dans le tiret, économisant probablement plusieurs microsecondes contre >foo. Si cela importe, le script Shell n'est pas le bon langage pour votre tâche !! Mais tu as demandé.


Avec l'atténuation Spectre + Meltdown activée, même un mauvais appel système -ENOSYS Prend au moins des milliers de cycles d'horloge, donc en microsecondes, sur un Intel x86-64 moderne. Au lieu de quelques centaines pour l'aller-retour utilisateur-> noyau-> utilisateur avec juste une instruction syscall. Bien sûr, les recherches de chemin et ainsi de suite prennent beaucoup de temps, tout comme le code du système de fichiers. Et passer en mode noyau et revenir en arrière évite souvent une partie du cache qui ralentit l'espace utilisateur au retour.

Le coût réel des E/S une fois que les métadonnées sont réécrites sur le disque dépend du système de fichiers. Un FS comme XFS ou ext4 moderne utilisant seulement 1 ou quelques extensions importantes pour le fichier entier peut facilement libérer d'énormes quantités d'espace en O(1) time Ou O(n) où n est le nombre d'extensions (fragmentation) et non la taille en octets.

Selon le FS, si les informations d'étendue ont été stockées directement dans l'inode, au lieu d'un bloc indirect, c'est une chose de moins à ajouter à la liste gratuite.

Le coût d'E/S est similaire à la dissociation du fichier, mais vous n'avez pas besoin de libérer l'inode ou de modifier l'entrée de répertoire. Vous devez toujours mettre à jour le mtime et le ctime dans l'inode lors de la troncature, mais vous devez quand même l'écrire si la taille change.

2
Peter Cordes