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?
Respuestas:
No puede hacer eso porque bash procesa las redirecciones primero y luego ejecuta el comando. Entonces, cuando grep mira file_name, ya está vacío. Sin embargo, puede utilizar un archivo temporal.
así, considere usar
mktemp
para crear el tmpfile pero tenga en cuenta que no es POSIX.fuente
>
redirección abrirá el archivo y lo truncará antes de que se inicie el shellgrep
.sponge
comando .Utilice esponja para este tipo de tareas. Es parte de moreutils.
Prueba este comando:
fuente
brew install moreutils
.sudo apt-get install moreutils
en sistemas basados en Debian.Utilice sed en su lugar:
fuente
-i
es solo una extensión de GNU, solo notando.-i ''
que la extensión no es estrictamente obligatoria, pero la-i
opción requiere algún argumento.prueba este simple
Su archivo no estará en blanco esta vez :) y su salida también se imprimirá en su terminal.
fuente
/dev/null
lugares similares.No puede usar el operador de redirección (
>
o>>
) al mismo archivo, porque tiene una prioridad más alta y creará / truncará el archivo incluso antes de que se invoque el comando. Para evitar esto, usted debe utilizar las herramientas adecuadas, tales comotee
,sponge
,sed -i
o cualquier otra herramienta que puede escribir resultados en el archivo (por ejemplosort file -o file
).Básicamente, redirigir la entrada al mismo archivo original no tiene sentido y debe usar los editores locales adecuados para eso, por ejemplo, Ex editor (parte de Vim):
dónde:
'+cmd'
/-c
- ejecutar cualquier comando Ex / Vimg/pattern/d
- eliminar líneas que coincidan con un patrón usando global (help :g
)-s
- modo silencioso (man ex
)-c wq
- ejecutar:write
y:quit
comandosUsted puede utilizar
sed
para lograr el mismo (como ya se ha mostrado en otras respuestas), sin embargo en el lugar (-i
) es la extensión de FreeBSD no estándar (pueden funcionar de forma diferente entre Unix / Linux) y básicamente se trata de un s TREAM ed itor, no un editor de archivos . Ver: ¿El modo Ex tiene algún uso práctico?fuente
Una alternativa de revestimiento: establezca el contenido del archivo como variable:
fuente
Dado que esta pregunta es el resultado principal en los motores de búsqueda, aquí hay una sola línea basada en https://serverfault.com/a/547331 que usa una subcapa en lugar de
sponge
(que a menudo no es parte de una instalación básica como OS X) :El caso general es:
Editar, la solución anterior tiene algunas advertencias:
printf '%s' <string>
debe usarse en lugar deecho <string>
para que los archivos que contienen-n
no causen un comportamiento no deseado.x
a la salida y eliminarlo en el exterior mediante la expansión de parámetros de una variable temporal como${v%x}
.$v
pisa fuerte el valor de cualquier variable existente$v
en el entorno de shell actual, por lo que debemos anidar toda la expresión entre paréntesis para preservar el valor anterior.null
de la salida. Verifiqué esto llamandodd if=/dev/zero bs=1 count=1 >> file_name
y viéndolo en hexadecimal concat file_name | xxd -p
. Peroecho $(cat file_name) | xxd -p
está despojado. Por lo tanto, esta respuesta no debe usarse en archivos binarios o cualquier cosa que use caracteres no imprimibles, como señaló Lynch .La solución general (aunque un poco más lenta, más memoria y aún eliminando caracteres no imprimibles) es:
Prueba de https://askubuntu.com/a/752451 :
Debería imprimir:
Mientras que llamar
cat file_uniquely_named.txt > file_uniquely_named.txt
al shell actual:Imprime una cadena vacía.
No lo he probado en archivos grandes (probablemente más de 2 o 4 GB).
He tomado prestada esta respuesta de Hart Simha y Kos .
fuente
cat
y lo coloca como primer argumento deecho
. Por supuesto, las variables no imprimibles no se generarán correctamente y dañarán los datos. No intente redirigir un archivo a sí mismo, simplemente no puede ser bueno.También hay
ed
(como alternativa ased -i
):fuente
Puede hacerlo mediante la sustitución de procesos .
Sin embargo, es un truco, ya que bash abre todas las tuberías de forma asincrónica y tenemos que
sleep
solucionarlo usando YMMV.En tu ejemplo:
>(sleep 1 && cat > file_name)
crea un archivo temporal que recibe la salida de grepsleep 1
se retrasa por un segundo para darle tiempo a grep para analizar el archivo de entradacat > file_name
escribe la salidafuente
Puede usar slurp con POSIX Awk:
Ejemplo
fuente
Esto es muy posible, solo tiene que asegurarse de que para cuando escriba la salida, la esté escribiendo en un archivo diferente. Esto se puede hacer eliminando el archivo después de abrirle un descriptor de archivo, pero antes de escribir en él:
O línea por línea, para entenderlo mejor:
Todavía es algo arriesgado, porque si COMMAND no se ejecuta correctamente, perderá el contenido del archivo. Eso se puede mitigar restaurando el archivo si COMMAND devuelve un código de salida distinto de cero:
También podemos definir una función de shell para que sea más fácil de usar:
Ejemplo:
Además, tenga en cuenta que esto mantendrá una copia completa del archivo original (hasta que se cierre el tercer descriptor de archivo). Si está utilizando Linux y el archivo en el que está procesando es demasiado grande para caber dos veces en el disco, puede consultar este script que canalizará el archivo al comando especificado bloque por bloque mientras desasigna el ya procesado bloques. Como siempre, lea las advertencias en la página de uso.
fuente
Prueba esto
fuente
Lo siguiente logrará lo mismo que
sponge
hace, sin requerirmoreutils
:La
--random-source=/dev/zero
parte engañashuf
para hacer lo suyo sin hacer ningún tipo de mezcla, por lo que almacenará en búfer su entrada sin alterarla.Sin embargo, es cierto que lo mejor es utilizar un archivo temporal por motivos de rendimiento. Entonces, aquí hay una función que he escrito que lo hará por usted de manera generalizada:
fuente
Normalmente uso el programa tee para hacer esto:
Crea y elimina un archivo temporal por sí mismo.
fuente
tee
no se garantiza que funcione. Consulte askubuntu.com/a/752451/335781 .