Esta es probablemente una solución compleja .
Estoy buscando un operador simple como ">>", pero para anteponer.
Me temo que no existe. Tendré que hacer algo como
mv myfile tmp cat myheader tmp> myfile
¿Algo más inteligente?
Esta es probablemente una solución compleja .
Estoy buscando un operador simple como ">>", pero para anteponer.
Me temo que no existe. Tendré que hacer algo como
mv myfile tmp cat myheader tmp> myfile
¿Algo más inteligente?
mktemp
? Siempre puedes limpiar el archivo temporal después ...Respuestas:
El truco a continuación fue una respuesta rápida que funcionó y recibió muchos votos positivos. Luego, a medida que la pregunta se hizo más popular y pasó más tiempo, la gente indignada comenzó a informar que funcionaba pero que cosas extrañas podrían suceder, o simplemente no funcionó en absoluto, por lo que se rechazó furiosamente por un tiempo. Que divertido
La solución explota la implementación exacta de los descriptores de archivos en su sistema y, debido a que la implementación varía significativamente entre los nixes, su éxito depende completamente del sistema, definitivamente no es portátil, y no se debe confiar en ella para nada incluso vagamente importante.
Ahora, con todo eso fuera del camino, la respuesta fue:
Crear otro descriptor de archivo para el archivo (
exec 3<> yourfile
) desde allí escribir en ese (>&3
) parece superar el dilema de lectura / escritura en el mismo archivo. Funciona para mí en archivos de 600K con awk. Sin embargo, intentar el mismo truco usando 'cat' falla.Pasar el prependage como una variable a awk (
-v TEXT="$text"
) supera el problema de las comillas literales que impide hacer este truco con 'sed'.fuente
Esto todavía usa un archivo temporal, pero al menos está en una línea:
Crédito: BASH: anteponer un texto / líneas a un archivo
fuente
-
despuéscat
?echo -n "text"
yourfile
es un enlace simbólico, esto no hará lo que desea.¡ed es el editor estándar! http://www.gnu.org/fun/jokes/ed.msg.html
fuente
0r header.file
echo -e '0a\nyour text here\n.\nw' | ed some_file
John Mee: no se garantiza que su método funcione, y probablemente fallará si antepone más de 4096 bytes de cosas (al menos eso es lo que sucede con gnu awk, pero supongo que otras implementaciones tendrán restricciones similares). No solo fallará en ese caso, sino que entrará en un bucle sin fin donde leerá su propia salida, haciendo crecer el archivo hasta que se llene todo el espacio disponible.
Pruébalo por ti mismo:
(advertencia: mátalo después de un tiempo o llenará el sistema de archivos)
Además, es muy peligroso editar archivos de esa manera, y es un consejo muy malo, ya que si algo sucede mientras el archivo se está editando (bloqueo, disco lleno) es casi seguro que se quedará con el archivo en un estado inconsistente.
fuente
No es posible sin un archivo temporal, pero aquí va un resumen
Puede usar otras herramientas como ed o perl para hacerlo sin archivos temporales.
fuente
Vale la pena señalar que a menudo es una buena idea generar de forma segura el archivo temporal utilizando una utilidad como mktemp , al menos si el script alguna vez se ejecutará con privilegios de root. Podría, por ejemplo, hacer lo siguiente (nuevamente en bash):
fuente
Si necesita esto en las computadoras que controla, instale el paquete "moreutils" y use "esponja". Entonces puedes hacer:
fuente
{ echo "prepended text"; cat myfile } | sponge myfile
Usando un bash heredoc puede evitar la necesidad de un archivo tmp:
Esto funciona porque $ (cat myfile) se evalúa cuando se evalúa el script bash, antes de que se ejecute el gato con redireccionamiento.
fuente
asumiendo que el archivo que desea editar es my.txt
Y el archivo que desea anteponer es encabezado
Asegúrese de tener una última línea en blanco en el archivo de encabezado.
Ahora puedes anteponerlo con
Terminas con
Hasta donde sé, esto solo funciona en 'bash'.
fuente
this is the header
en my.txt. Incluso después de actualizar Bash4.3.42(1)-release
, obtengo el mismo resultado.<(...)
) , por lo que no hay garantía de quemy.txt
se lea por completo , sin lo cual esta técnica no funcionará.Cuando comience a intentar hacer cosas que se vuelven difíciles en el script de shell, le sugiero encarecidamente que busque reescribir el script en un lenguaje de script "adecuado" (Python / Perl / Ruby / etc.)
En cuanto a anteponer una línea a un archivo, no es posible hacer esto a través de una tubería, ya que cuando hace algo así
cat blah.txt | grep something > blah.txt
, inadvertidamente pone el archivo en blanco. Hay un pequeño comando de utilidad llamadosponge
que puede instalar (lo hacecat blah.txt | grep something | sponge blah.txt
y almacena el contenido del archivo, luego lo escribe en el archivo). Es similar a un archivo temporal, pero no tiene que hacerlo explícitamente. pero yo diría que es un requisito "peor" que, por ejemplo, Perl.Puede haber una manera de hacerlo a través de awk o similar, pero si tiene que usar shell-script, creo que un archivo temporal es, con mucho, la forma más fácil (¿/ solo?).
fuente
Como sugiere Daniel Velkov, usa tee.
Para mí, esa es una solución inteligente simple:
fuente
EDITAR: Esto está roto. Vea Comportamiento extraño al anteponer un archivo con cat y tee
La solución al problema de sobrescritura está usando
tee
:fuente
El que yo uso. Este le permite especificar el orden, los caracteres adicionales, etc. de la manera que desee:
PD: solo no funciona si los archivos contienen texto con barra invertida, porque se interpreta como caracteres de escape
fuente
Principalmente por diversión / golf de conchas, pero
hará el truco, y no hay tuberías ni redireccionamientos. Por supuesto, vi / ex no es realmente para uso no interactivo, por lo que vi parpadeará brevemente.
fuente
¿Por qué no simplemente usar el comando ed (como ya sugirió Fluffle aquí)?
¡ed lee todo el archivo en la memoria y realiza automáticamente una edición in situ del archivo!
Entonces, si su archivo no es tan grande ...
Otra solución alternativa sería utilizar identificadores de archivos abiertos como lo sugiere Jürgen Hötzel en la salida Redirect de sed 's / c / d /' myFile a myFile
Todo esto podría ponerse en una sola línea, por supuesto.
fuente
Una variante en la solución de cb0 para "sin archivo temporal" para anteponer texto fijo:
Una vez más, esto se basa en la ejecución de sub-shell (the (..)) para evitar que el gato se niegue a tener el mismo archivo para entrada y salida.
Nota: me gustó esta solución. Sin embargo, en mi Mac, el archivo original se pierde (pensé que no debería, pero lo hace). Eso podría solucionarse escribiendo su solución como: echo "texto para anteponer" | cat - file_to_be_modified | cat> archivo_mp; mv tmp_file file_to_be_modified
fuente
Esto es lo que descubrí:
fuente
fuente
ADVERTENCIA: esto necesita un poco más de trabajo para satisfacer las necesidades del OP.
Debería haber una manera de hacer que el enfoque sed de @shixilun funcione a pesar de sus dudas. Debe haber un comando bash para escapar del espacio en blanco al leer un archivo en una cadena de sustitución sed (por ejemplo, reemplazar caracteres de nueva línea con '\ n'. Comandos de shell
vis
ycat
puede tratar con caracteres no imprimibles, pero no espacios en blanco, por lo que esto no resolverá los OP problema:falla debido a las nuevas líneas sin procesar en el guión sustituto, que deben anteponerse con un carácter de continuación de línea () y tal vez seguido de un &, para mantener el shell y quedar contento, como esta respuesta SO
sed
tiene un límite de tamaño de 40 K para los comandos de reemplazo de búsqueda no global (sin seguimiento / g después del patrón), por lo que probablemente evitaría los problemas de desbordamiento del búfer de miedo de awk que advirtió anónimo.fuente
fuente
Con $ (comando) puede escribir la salida de un comando en una variable. Entonces lo hice en tres comandos en una línea y sin archivo temporal.
fuente
Si tiene un archivo grande (unos pocos cientos de kilobytes en mi caso) y acceso a Python, esto es mucho más rápido que
cat
las soluciones de tubería:python -c 'f = "filename"; t = open(f).read(); open(f, "w").write("text to prepend " + t)'
fuente
Una solución con
printf
:También puedes hacer:
Pero en ese caso, debe asegurarse de que no haya ninguno
%
, incluido el contenido del archivo de destino, ya que puede interpretarse y arruinar sus resultados.fuente
echo
Parece una opción más segura.echo "my new line\n$(cat my/file.txt)" > my/file.txt
${new_line}
, no el archivo de destinoPuede usar la línea de comando perl:
Donde -i creará un reemplazo en línea del archivo y -0777 sorberá todo el archivo y hará que ^ coincida solo con el principio. -pe imprimirá todas las líneas
O si my_header es un archivo:
Donde / e permitirá una evaluación de código en la sustitución.
fuente
donde "my_file" es el archivo al que anteponer "my_string".
fuente
Me gusta el enfoque de @ fluffle's ed . Después de todo, los cambios de línea de comando de cualquier herramienta frente a los comandos de editor con script son esencialmente lo mismo aquí; no ver una solución de editor de secuencias de comandos "limpieza" es menor o no.
Aquí está mi línea única añadida para
.git/hooks/prepare-commit-msg
anteponer un.gitmessage
archivo en el repositorio para enviar mensajes:Ejemplo
.gitmessage
:Estoy haciendo en
1r
lugar de0r
, porque eso dejará la línea vacía lista para escribir en la parte superior del archivo de la plantilla original. No pongas una línea vacía encima de la tuya.gitmessage
, terminarás con dos líneas vacías.-s
suprime la salida de información de diagnóstico de ed.En relación con esto, descubrí que para vim-buffs también es bueno tener:
fuente
variables, ftw?
fuente
Creo que esta es la variación más limpia de ed:
como una función:
fuente
Si está escribiendo scripts en BASH, en realidad, puede emitir:
Eso está realmente en el ejemplo complejo que usted mismo publicó en su propia pregunta.
fuente
cat - yourfile <<<"text" > /tmp/out && mv /tmp/out yourfile
, sin embargo, eso es lo suficientemente diferente de mi respuesta como para que sea su propia respuesta.En mi humilde opinión, no hay una solución de shell (y nunca será una) que funcione de manera consistente y confiable independientemente de los tamaños de los dos archivos
myheader
ymyfile
. La razón es que si desea hacerlo sin recurrir a un archivo temporal (y sin dejar que el shell se repita silenciosamente a un archivo temporal, por ejemplo, a través de construcciones comoexec 3<>myfile
, canalizar atee
, etc.)La solución "real" que está buscando debe jugar con el sistema de archivos, por lo que no está disponible en el espacio de usuario y dependerá de la plataforma: está solicitando modificar el puntero del sistema de archivos en uso según
myfile
el valor actual del puntero del sistema de archivos paramyheader
y reemplazar en el sistemaEOF
de archivos demyheader
con un enlace encadenado a la dirección del sistema de archivos actual señalado pormyfile
. Esto no es trivial y obviamente no puede ser hecho por un no superusuario, y probablemente tampoco por el superusuario ... Jugar con inodes, etc.Sin embargo, puedes simular esto más o menos usando dispositivos de bucle. Ver por ejemplo este hilo SO .
fuente