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
ycat 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 comocat 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 escribirF
antes de que elcat
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