Est-ce que trier prend en charge le tri d'un fichier sur place, comme `sed - in-place`?

80

Suis-je aveugle ou n'y a-t-il pas d'option comme --in-placepour sort?

Afin de sauvegarder les résultats dans le fichier d’entrée, sed utilise -i( --in-place).

Rediriger la sortie de sortvers le fichier d'entrée

sort < f > f

a pour résultat de le rendre vide. S'il n'y a pas d' --in-placeoption - peut-être y a-t-il une astuce pour faire cela d'une manière pratique ?

(La seule chose qui me vienne à l’esprit:

sort < f > /tmp/f$$ ; cat /tmp/f$$ > f ; rm /tmp/f$$

Déplacer n’est pas un choix judicieux, les autorisations sur les fichiers peuvent être modifiées. C'est pourquoi j'écrase le contenu du fichier temporaire que je supprime ensuite.)

Grzegorz Wierzowiecki
la source
Il existe également insitu, permettant à toutes les commandes d'être utilisées sur place.
Sr.
@sr_, c'est une commande intéressante, mais elle ne fonctionne avec aucune commande, seulement avec celles qui n'écrivent pas plus vite qu'elles ne lisent (sinon, le fichier d'entrée sera obstrué avant que la commande ne le lise). Il n'y a aucune garantie que cela fonctionne sort.
cjm
@ cjm, je ne suis vraiment pas sûr, mais n'est- ce pas supposé gérer ce cas?
Sr.
@sr_, je pense que tu as raison. J'ai lu la description au lieu de regarder la source. Bien que pour les fichiers très volumineux, la mémoire tampon et la mémoire tampon risquent de manquer de mémoire (il ne semble pas que cela vérifie si la valeur renvoyée par malloc est NULL).
cjm
@ cjm: Oh oui, en effet.
Sr.

Réponses:

110

sorta l' -o, --outputoption qui prend un nom de fichier en argument. S'il est identique au fichier d'entrée, le résultat est écrit dans un fichier temporaire, puis le fichier d'origine est écrasé (exactement la même chose que ce qui est sed -ifait).

De la GNU sortpage d'information:

`-o OUTPUT-FILE'
`--output=OUTPUT-FILE'
      Write output to OUTPUT-FILE instead of standard output.  Normally,
      `sort' reads all input before opening OUTPUT-FILE, so you can
      safely sort a file in place by using commands like `sort -o F F'
      and `cat F | sort -o F'.  However, `sort' with `--merge' (`-m')
      can open the output file before reading all input, so a command
      like `cat F | sort -m -o F - G' is not safe as `sort' might start
      writing `F' before `cat' is done reading it.

      On newer systems, `-o' cannot appear after an input file if
      `POSIXLY_CORRECT' is set, e.g., `sort F -o F'.  Portable scripts
      should specify `-o OUTPUT-FILE' before any input files.

et de The Open Group Base Specifications Issue 7 :

-o  output
    Specify the name of an output file to be used instead of the standard 
    output. This file can be the same as one of the input files.
enzotib
la source
Exactement ! Ça marche ! Je ne vois aucun indice à ce sujet dans man sort- est-ce une fonctionnalité non documentée? Est-ce standard et portable?
Grzegorz Wierzowiecki
@GrzegorzWierzowiecki: voir mise à jour.
enzotib
Bonne réponse :).
Grzegorz Wierzowiecki
1
En résumé: sort -o <filename> <filename>va trier en toute sécurité un fichier en place.
Phyatt
11

Vous pouvez utiliser la spongefonction, qui imbibe d'abord le stdin, puis l'écrit dans un fichier, comme:

sort < f | sponge f

L'inconvénient spongeest qu'il stockera temporairement la sortie dans la mémoire, ce qui peut poser problème pour les gros fichiers. Sinon, vous devez d'abord l'écrire dans un fichier, puis écraser le fichier d'origine.

Comme le soulignent d’autres réponses, les modifications sur place ne sont généralement pas une bonne idée, car au milieu d’un processus (celui par exemple sponge), la machine risque de tomber en panne et de perdre le fichier original et le nouveau. Vous feriez mieux de l'écrire d'abord dans un fichier différent, puis d'utiliser une mvinstruction atomique (déplacer).

Willem Van Onsem
la source
7

Il est dangereux de remplacer le fichier d'entrée par le fichier de sortie, car si le programme ou le système se bloque pendant l'écriture du fichier, vous avez perdu les deux.

Quelques programmes (principalement les versions GNU) ont une option in-situ (par exemple -i, perl et GNU sed; -osur le type GNU). Ils travaillent en plaçant les données dans un fichier temporaire, puis en les déplaçant. Pour les programmes qui n'ont pas cette option, Colin Watson spongeutilitaire (inclus dans les moreutils de Joey Hess ) fait le travail en toute sécurité pour tout programme (exemples: Puis - je faire cut? Modifier un fichier en place , Comment puis - je faire iconv remplacer le fichier d'entrée avec le converti sortie? ).

Dans les rares cas où vous ne pouvez pas recréer le fichier d'origine avec les mêmes autorisations, je vous recommande de remplacer le fichier en place. Dans ce cas, vous feriez mieux de sauvegarder l’entrée originale quelque part. Ensuite, vous pouvez simplement traiter la copie de l’entrée et l’envoyer dans le fichier original.

cp -p f ~/f.backup
sort <~/f.backup >|f
rm ~/f.backup # optional
Gilles, arrête de faire le mal
la source
1
sort -on’est pas spécifique à GNU et est spécialement conçu pour effectuer une rotation générale du fichier en place. sortne peut pas commencer à écrire sa sortie avant d’avoir lu toutes ses entrées (utilise de la mémoire ou des fichiers temporaires pour stocker des données), il est donc tout à fait naturel qu’elle puisse remplacer son entrée.
Stéphane Chazelas
Et en fait, c’est un cas où GNU sortn’est pas POSIX, car il sort -mo file1 file1 file2n’est pas garanti que cela fonctionne, alors que les sortgens traditionnels savent comment contourner ce problème (déjà sous Unix V7 dans les années 70).
Stéphane Chazelas
@JoelCross Odd, sort -otravaille pour moi avec coreutils 8.25 et la propriété est documentée dans le manuel (notez que ce n'est que le cas lors du tri, pas lors de la fusion). Si vous pouvez le reproduire, envoyez un rapport de bogue (indiquant la ligne de commande exacte, le ou les fichiers d'entrée exacts, le système sur lequel vous l'exécutez et comment vous avez obtenu le binaire).
Gilles, arrête de faire le mal
4

Utilisez -oou essayez vim-way:

$ ex -s +'%!sort' -cxa file.txt
Kenorb
la source