Ordenación única: redirige la salida al mismo archivo


14

¿Hay alguna forma corta de guardar la salida de la tubería en el mismo archivo que se procesa? Por ejemplo, esto es lo que realmente estoy haciendo.

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

Me preguntaba si había una manera de hacerlo en una sola línea (sin agregar esos comandos usando &&)

Este no es el camino, pero para tener una idea

$ cat filename | sort | uniq > filename

2
echo $(cat filename | sort | uniq > result) > filenameo algo ? De paso, no tengo tiempo para probarlo.
MrVaykadji

Respuestas:


18

Se puede utilizar spongedesde moreutils paquete:

LC_ALL=C sort -u filename | sponge filename

Tampoco necesita tubería uniq, ya que cuando sorttiene la -uopción de líneas únicas al ordenar.

Tenga en cuenta que en el sistema GNU con configuraciones regionales UTF-8, sort -uo sort | uniqno le dio líneas únicas, sino la primera de la secuencia de líneas que clasifican lo mismo en la configuración regional actual.

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

que dio solamente . Cambiar la configuración regional a C fuerza el orden de clasificación en función de los valores de bytes:

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


12

No es necesario ningún comando extra, como caty uniqtambién sin necesidad de utilizar rmel mando y mvcomando para quitar y cambiar el nombre del nombre de archivo. solo usa un comando 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

¿Como funciona?

sortEl comando ordena su nombre de archivo y, con la -uopción, elimina las líneas duplicadas. luego con la -oopción escribe la salida en el mismo archivo con el método in situ.


3
Si el sistema falla cuando se sortestá ejecutando, perderá su archivo original.
Cuonglm

@Gnouc ¡Entonces, este es el final de la mala suerte! : '(
αғsнιη

1
¡Gracias! en este ejemplo, con "ordenar" en particular, debería hacer eso. Sin embargo, estaba pensando en un caso general. @Gnouc, jaja, no hay forma de pensar que si no te hubiera pasado, ¿verdad?
whitenoisedb

3

Su ejemplo sugerido (a continuación) no funciona porque en realidad estaría leyendo y escribiendo en el mismo archivo simultáneamente.

$ cat filename | sort | uniq > filename

La idea con una tubería o redirección es que el comando en el lado izquierdo y derecho de cada tubería o redirección se ejecute simultáneamente, en paralelo. El comando de la derecha procesa la información a medida que se le entrega desde el comando de la izquierda, mientras que el comando de la izquierda todavía se está ejecutando.

Para que su escenario funcione, el comando que lee del archivo debería finalizar antes de que comience el comando que escribe en el archivo. Para que esto funcione, primero debe redirigir la salida a una ubicación temporal, luego, una vez que haya terminado, envíela desde la ubicación temporal nuevamente al archivo.

Una mejor manera de hacer esto es básicamente como en su ejemplo anterior, donde redirige a un archivo temporal y luego cambia el nombre del archivo al original (excepto que no necesita eliminar el archivo primero, porque al moverlo se elimina cualquier objetivo existente) .

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

También puede guardarlo en una variable de cadena, excepto que solo funciona cuando los datos son lo suficientemente pequeños como para que quepan todos en la memoria a la vez.


Como alguien publicó en una edición sugerida, puede cambiar cat filename | sorta solo sort filename: cates innecesario aquí.
thomasrutter

Mi ejemplo a continuación no era la forma de hacerlo. Gracias por la aclaración. catpodría ser innecesario en este caso, pero me estaba centrando en la parte de redirección.
whitenoisedb

1
Estaba explicando por qué el siguiente ejemplo no funcionaría. Sé que sabías que no funcionó.
thomasrutter

¡Gracias por aclararlo! De hecho, no sabía lo que realmente estaba sucediendo.
whitenoisedb

2

Puedes usar el teecomando:

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

El teecomando lee de la entrada estándar y escribe en la salida y los archivos estándar .


2
Esto no funciona para mi.
pjvandehaar

3

Esto hace el trabajo para mí. por ejemplo, mover una línea al final de un archivo: (cat ~/file | grep -v 3662 ; printentry 3662) | tee ~/file > /dev/nullfunciona. Al igual que el post original, esto no funciona si sólo > ~/filesin el tee. Tee parece similar aquí sort -o file, que escribe en el archivo nombrado sin continuar la misma tubería.
Joshua Goldberg el

Espera, lo siento! He visto empíricamente que esto perderá datos de forma impredecible como se explica en el enlace de @Steven. Haga un archivo con los números 1..9 en 9 líneas. Lo siguiente funcionará varias veces, y luego ocasionalmente eliminará todos los datos del archivo: (cat x | grep -v 7 ; echo 7) | tee x > /dev/null; cat x recomiendo un archivo temporal y / mvo tal vez la solución del enlace de @ Steven.
Joshua Goldberg

@ JoshuaGoldberg, ¿has visto mi respuesta en esta página?
Steven Penny

0

Puede usar Vim en modo Ex:

ex -sc 'sort u|x' filename
  1. sort u tipo único

  2. x escriba si se han realizado cambios (lo han hecho) y salga

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.