sort column alphabetically bash command-line sorting

column - ¿Cómo ejecuto algún comando editando su archivo(argumento) "en su lugar" usando bash?



sort linux command syntax (14)

Tengo un archivo temp.txt, que quiero ordenar con el comando sort en bash.

Quiero que los resultados ordenados reemplacen el archivo original.

Esto no funciona, por ejemplo (obtengo un archivo vacío):

sortx temp.txt > temp.txt

¿Se puede hacer esto en una línea sin recurrir a la copia de archivos temporales?

EDITAR: La opción -o es genial para sort . Usé el sort en mi pregunta como un ejemplo. Me encuentro con el mismo problema con otros comandos:

uniq temp.txt > temp.txt.

¿Hay una mejor solución general?


Aquí hay un enfoque más general, funciona con uniq, sort y whatnot.

{ rm file && uniq > file; } < file


Aquí tienes, una línea:

sort temp.txt > temp.txt.sort && mv temp.txt.sort temp.txt

Técnicamente no hay copia en un archivo temporal, y el comando ''mv'' debe ser instantáneo.


Esto sería muy limitado de memoria, pero podría usar awk para almacenar los datos intermedios en la memoria, y luego escribirlos de nuevo.

uniq temp.txt | awk ''{line[i++] = $0}END{for(j=0;j<i;j++){print line[j]}}'' > temp.txt


Lea en el editor no interactivo, ex .


Me gusta el sort file -o file respuesta, pero no quiero escribir el mismo nombre de archivo dos veces.

Usando la expansión de la historia de BASH:

$ sort file -o !#^

toma la primera arg de la línea actual cuando presiona enter .

Un tipo único en el lugar:

$ sort -u -o file !#$

agarra el último arg en la línea actual.


Muchos han mencionado la opción -o . Aquí está la parte de la página man.

Desde la página man:

-o output-file Write output to output-file instead of to the standard output. If output-file is one of the input files, sort copies it to a temporary file before sorting and writing the output to output- file.


Otra solución:

uniq file 1<> file


Para agregar la capacidad de uniq , ¿cuáles son las desventajas de:

sort inputfile | uniq | sort -o inputfile


Si insiste en usar el programa de sort , debe usar un archivo intermedio; no creo que el sort tenga una opción para ordenar en la memoria. Cualquier otro truco con stdin / stdout fallará a menos que pueda garantizar que el tamaño del búfer para el stdin de ordenación es lo suficientemente grande como para caber todo el archivo.

Editar: lástima de mí. sort temp.txt -o temp.txt funciona excelente.


Una sort necesita ver todas las entradas antes de que pueda comenzar a emitirse. Por este motivo, el programa de sort puede ofrecer fácilmente una opción para modificar un archivo in situ:

sort temp.txt -o temp.txt

Específicamente, la documentación del sort GNU dice:

Normalmente, ordena todas las entradas antes de abrir el archivo de salida, por lo que puede ordenar con seguridad un archivo en su lugar mediante comandos como sort -o FF y cat F | sort -o F cat F | sort -o F Sin embargo, sort con --merge ( -m ) puede abrir el archivo de salida antes de leer todas las entradas, por lo que un comando como cat F | sort -m -o F - G cat F | sort -m -o F - G no es seguro ya que el género podría comenzar a escribir F antes de que el cat termine de leerlo.

Mientras que la documentación de BSD sort :

Si [el] archivo de salida es uno de los archivos de entrada, ordénelo en un archivo temporal antes de ordenar y escribir el resultado en [el] archivo de salida.

Los comandos como uniq pueden comenzar a escribir la salida antes de que terminen de leer la entrada. Estos comandos generalmente no son compatibles con la edición in situ (y sería más difícil para ellos admitir esta característica).

Por lo general, soluciona esto con un archivo temporal, o si desea evitar tener un archivo intermedio, puede usar un búfer para almacenar el resultado completo antes de escribirlo. Por ejemplo, con perl :

uniq temp.txt | perl -e ''undef $/; $_ = <>; open(OUT,">temp.txt"); print OUT;''

Aquí, la parte perl lee el resultado completo de uniq en la variable $_ y luego sobrescribe el archivo original con esta información. Podrías hacer lo mismo en el lenguaje de scripting que elijas, quizás incluso en Bash. Pero tenga en cuenta que necesitará suficiente memoria para almacenar todo el archivo, esto no es recomendable cuando se trabaja con archivos de gran tamaño.


Una alternativa a la sponge con el sed más común:

sed -ni r<(command file) file

Funciona para cualquier comando ( sort , uniq , tac , ...) y utiliza la muy conocida opción s -i (editar archivos in situ).

Advertencia: pruebe primero con el command file porque la edición de archivos en el lugar no es segura por naturaleza.

Explicación

En primer lugar, le está diciendo a sed no imprima las líneas (originales) ( opción -n ), y con la ayuda del comando r sed y la sustitución de procesos de bash , el contenido generado por <(command file) será la salida guardada en su lugar .

Hacer las cosas aún más fáciles

Puede envolver esta solución en una función:

ip_cmd() { # in place command CMD=${1:?You must specify a command} FILE=${2:?You must specify a file} sed -ni r<("$CMD" "$FILE") "$FILE" }

Ejemplo

$ cat file d b c b a $ ip_cmd sort file $ cat file a b b c d $ ip_cmd uniq file $ cat file a b c d $ ip_cmd tac file $ cat file d c b a $ ip_cmd bash: 1: You must specify a command $ ip_cmd uniq bash: 2: You must specify a file


Usa el argumento --output= o -o

Acabo de probar FreeBSD:

sort temp.txt -otemp.txt


El comentario de Tobu sobre la esponja justifica ser una respuesta en sí misma.

Para citar de la página de inicio de moreutils :

Probablemente la herramienta más general en moreutils hasta ahora es sponge (1), que te permite hacer cosas como esta:

% sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd

Sin embargo, sponge sufre del mismo problema que Steve Jessop comenta aquí. Si alguno de los comandos en la tubería antes de la sponge falla, entonces se escribirá el archivo original.

$ mistyped_command my-important-file | sponge my-important-file mistyped-command: command not found

Uh-oh, my-important-file se ha ido.


sort temp.txt -o temp.txt