Tri unique: redirigez la sortie vers le même fichier

14

Existe-t-il un moyen rapide d'enregistrer la sortie du tuyau dans le même fichier que celui traité. Par exemple, c'est ce que je fais réellement

$ cat filename | sort | uniq > result
$ rm -f filename
$ mv result filename

Je me demandais s'il y avait un moyen de le faire en une seule ligne (sans ajouter ces commandes en utilisant &&)

Ce n'est pas comme ça, mais pour se faire une idée

$ cat filename | sort | uniq > filename
whitenoisedb
la source
2
echo $(cat filename | sort | uniq > result) > filenameou quelque chose ? Juste en passant, je n'ai pas le temps de l'essayer.
MrVaykadji

Réponses:

18

Vous pouvez utiliser à spongepartir du package moreutils :

LC_ALL=C sort -u filename | sponge filename

Vous n'avez également pas besoin de tuyau uniq, car quand sorta l' -uoption de lignes uniques lors du tri.

Notez que sur un système GNU avec des locales UTF-8, sort -uou sort | uniqne vous a pas donné de lignes uniques, mais la première d'une séquence de lignes qui les trient de la même manière dans les locales actuelles.

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=en_US.utf8 sort | LC_ALL=en_US.utf8 uniq

vous a donné seulement . Changer les paramètres régionaux en C force l'ordre de tri en fonction des valeurs d'octets:

$ export LC_ALL=C
$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C sort | LC_ALL=C uniq

cuonglm
la source
12

Vous n'avez besoin d'aucune commande supplémentaire comme catet uniqet également sans utiliser la rmcommande et la mvcommande pour supprimer et renommer le nom de fichier. utilisez simplement une commande simple.

sort -u filename -o filename


 -u, --unique
        with -c, check for strict ordering; without -c, output only  the
        first of an equal run

 -o, --output=FILE
        write result to FILE instead of standard output

Comment ça marche?

sortcommande trie votre nom de fichier et avec -uoption, supprime les lignes en double. puis avec -ooption écrit la sortie dans le même fichier avec la méthode sur place.

αғsнιη
la source
3
Si le système plante lors de sortson exécution, vous perdrez votre fichier d'origine.
cuonglm
@Gnouc Donc, c'est la fin de la malchance !! : '(
αғsнιη
1
Merci! dans cet exemple, avec «tri» en particulier, je devrais le faire. Cependant, je pensais à un cas général. @Gnouc, haha, il n'y a aucun moyen de penser que si cela ne vous arrivait pas, non?
whitenoisedb
3

L'exemple que vous avez suggéré (ci-dessous) ne fonctionne pas, car vous seriez en train de lire et d'écrire dans le même fichier simultanément.

$ cat filename | sort | uniq > filename

L'idée avec un tuyau ou une redirection est que la commande à gauche et à droite de chaque tuyau ou redirection s'exécute simultanément, en parallèle. La commande de droite traite les informations telles qu'elles leur sont transmises par la commande de gauche, tandis que la commande de gauche est toujours en cours d'exécution.

Pour que votre scénario fonctionne, la commande qui lit à partir du fichier doit se terminer avant que la commande qui écrit dans le fichier ne commence. Pour que cela fonctionne, vous devez d'abord rediriger la sortie vers un emplacement temporaire, puis une fois terminé, renvoyez-la de l'emplacement temporaire dans le fichier.

Une meilleure façon de le faire est essentiellement comme dans votre exemple précédent, où vous redirigez vers un fichier temporaire, puis renommez ce fichier à l'original (sauf que vous n'avez pas besoin de supprimer le fichier d'abord, car le déplacement supprime toute cible existante) .

$ cat filename | sort | uniq > result
$ mv -f result filename

Vous pouvez également l'enregistrer dans une variable de chaîne, sauf que cela ne fonctionne que lorsque les données sont suffisamment petites pour toutes tenir en mémoire à la fois.

thomasrutter
la source
Comme quelqu'un a publié une modification suggérée, vous pouvez passer cat filename | sortà simplement sort filename- catn'est pas nécessaire ici.
thomasrutter
Mon exemple ci-dessous n'était pas la façon de le faire. Merci pour la clarification. catpourrait être inutile dans ce cas, mais je me concentrais sur la partie de redirection.
whitenoisedb
1
J'expliquais pourquoi votre exemple ci-dessous ne fonctionnerait pas. Je sais que tu savais que ça ne fonctionnait pas.
thomasrutter
Merci de clarifier! En fait, je ne savais pas ce qui se passait vraiment.
whitenoisedb
2

Vous pouvez utiliser la teecommande:

sort -u filename | tee filename > /dev/null

La teecommande lit à partir de l'entrée standard et écrit sur la sortie standard et les fichiers.

Sylvain Pineau
la source
2
Cela ne fonctionne pas pour moi.
pjvandehaar
3
Cela ne fonctionne pas askubuntu.com/a/752451
Steven Penny
Cela fait le travail pour moi. par exemple, pour déplacer une ligne vers le bas d'un fichier: (cat ~/file | grep -v 3662 ; printentry 3662) | tee ~/file > /dev/nullfonctionne. Comme le message d'origine, cela ne fonctionne pas si vous venez > ~/filesans le tee. Tee semble similaire à ici sort -o file, qui écrit dans le fichier nommé sans continuer le même canal.
Joshua Goldberg
Attends, désolé! J'ai vu empiriquement que cela perdrait de manière imprévisible des données comme expliqué dans le lien de @Steven. Faites un fichier avec les chiffres 1 à 9 sur 9 lignes. Ce qui suit fonctionnera plusieurs fois, puis supprimera occasionnellement toutes les données du fichier: (cat x | grep -v 7 ; echo 7) | tee x > /dev/null; cat x je recommande un fichier temporaire et / mvou peut-être la solution du lien de @ Steven.
Joshua Goldberg
@JoshuaGoldberg avez-vous vu ma réponse sur cette page?
Steven Penny
0

Vous pouvez utiliser Vim en mode Ex:

ex -sc 'sort u|x' filename
  1. sort u trier unique

  2. x écrire si des modifications ont été apportées (elles l'ont été) et quitter

Steven Penny
la source