tuberias salida guardar filtros crear comandos comando archivo bash redirect io

bash - salida - tuberias linux



¿Cómo puedo usar un archivo en un comando y redireccionar el resultado al mismo archivo sin truncarlo? (11)

Básicamente, quiero tomar como entrada el texto de un archivo, eliminar una línea de ese archivo y enviar la salida al mismo archivo. Algo en esta línea si eso lo aclara.

grep -v ''seg[0-9]/{1,/}/.[0-9]/{1/}'' file_name > file_name

sin embargo, cuando hago esto termino con un archivo en blanco. ¿Alguna idea?


No puede hacer eso porque bash procesa primero las redirecciones y luego ejecuta el comando. Entonces, cuando grep mira file_name, ya está vacío. Sin embargo, puedes usar un archivo temporal.

grep -v ''seg[0-9]/{1,/}/.[0-9]/{1/}'' file_name > tmpfile cat tmpfile > file_name

así, considere usar mktemp para crear el tmpfile pero tenga en cuenta que no es POSIX.


No puede usar el operador de redirección ( > o >> ) en el mismo archivo, porque tiene una precedencia más alta y creará / truncará el archivo incluso antes de invocar el comando. Para evitar eso, debe usar las herramientas apropiadas, como tee , sponge , sed -i o cualquier otra herramienta que pueda escribir resultados en el archivo (por ejemplo, sort file -o file ).

Básicamente, redirigir la entrada al mismo archivo original no tiene sentido y debe usar editores in situ apropiados para eso, por ejemplo, el editor Ex (parte de Vim):

ex ''+g/seg[0-9]/{1,/}/.[0-9]/{1/}/d'' -scwq file_name

dónde:

  • ''+cmd'' / -c - ejecuta cualquier comando Ex / Vim
  • g/pattern/d - eliminar líneas que coincidan con un patrón usando global ( help :g )
  • -s - modo silencioso ( man ex )
  • -c wq - execute :write y :quit comandos

Puede usar sed para lograr lo mismo (como ya se ha mostrado en otras respuestas), sin embargo in-situ ( -i ) es una extensión de FreeBSD no estándar (puede funcionar de forma diferente entre Unix / Linux) y básicamente es un editor sísmico, no un editor de archivos. Ver: ¿El modo Ex tiene algún uso práctico?


Puedes hacer eso usando process-substitution .

Sin embargo, es un poco complicado, ya que bash abre todas las canalizaciones de forma asíncrona y tenemos que trabajar en eso utilizando sleep modo YMMV.

En tu ejemplo:

grep -v ''seg[0-9]/{1,/}/.[0-9]/{1/}'' file_name > >(sleep 1 && cat > file_name)

  • >(sleep 1 && cat > file_name) crea un archivo temporal que recibe la salida de grep
  • sleep 1 demora por un segundo para dar tiempo grep para analizar el archivo de entrada
  • finalmente cat > file_name escribe la salida

Puedes usar slurp con POSIX Awk:

!/seg[0-9]/{1,/}/.[0-9]/{1/}/ { q = q ? q RS $0 : $0 } END { print q > ARGV[1] }

Example


También hay ed (como una alternativa a sed -i ):

# cf. http://wiki.bash-hackers.org/howto/edit-ed printf ''%s/n'' H ''g/seg[0-9]/{1,/}/.[0-9]/{1/}/d'' wq | ed -s file_name


Una alternativa de línea alternativa: configure el contenido del archivo como variable:

VAR=`cat file_name`; echo "$VAR"|grep -v ''seg[0-9]/{1,/}/.[0-9]/{1/}'' > file_name


Use sed en su lugar:

sed -i ''/seg[0-9]/{1,/}/.[0-9]/{1/}/d'' file_name


Use una sponge para este tipo de tareas. Es parte de moreutils.

Pruebe este comando:

grep -v ''seg[0-9]/{1,/}/.[0-9]/{1/}'' file_name | sponge file_name


Usualmente uso el programa de tee para hacer esto:

grep -v ''seg[0-9]/{1,/}/.[0-9]/{1/}'' file_name | tee file_name

Crea y elimina un archivo temporal por sí mismo.


intenta esto simple

grep -v ''seg[0-9]/{1,/}/.[0-9]/{1/}'' file_name | tee file_name

Su archivo no estará en blanco esta vez :) y su resultado también se imprimirá en su terminal.


tal vez puedas hacerlo así:

grep -v ''seg[0-9]/{1,/}/.[0-9]/{1/}'' file_name | cat > file_name