¿Cómo agrego texto al comienzo de un archivo en Bash?


285

Hola, quiero anteponer texto a un archivo. Por ejemplo, quiero agregar tareas al comienzo de un archivo todo.txt. Soy consciente, echo 'task goes here' >> todo.txtpero eso agrega la línea al final del archivo (no es lo que quiero).


2
Si no hay una manera eficiente de hacerlo para archivos grandes: unix.stackexchange.com/questions/87772/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

@ ¿podría echar un vistazo a este método superuser.com/a/1352628/11116
Evan Carroll

Respuestas:


374
echo 'task goes here' | cat - todo.txt > temp && mv temp todo.txt

o

sed -i '1s/^/task goes here\n/' todo.txt

o

sed -i '1itask goes here' todo.txt

44
¡el primero funciona muy bien! ¿te importaría explicar la lógica? No estoy particularmente seguro de cómo interpretar la sintaxis.
user479534

44
@ user8347: Canalice ( |) el mensaje ( echo '...') catque utiliza -(entrada estándar) como primer archivo y todo.txtcomo segundo. catConcatena múltiples archivos. Envíe la salida ( >) a un archivo llamado temp. Si no hay errores ( &&) desde catentonces, cambie el nombre ( mv) del temparchivo al archivo original ( todo.txt).
Dennis Williamson

1
@itaifrenkel: Tendría que ver lo que hiciste, pero si catrecibe una barra invertida literal n, no la convertirá en una nueva línea. Algo más debe haber hecho eso. En lugar de cat, intente hexdump -Cver si realmente está enviando una barra invertida y no si es una nueva línea. También puede intentar cat -emostrar los finales de línea.
Dennis Williamson

1
Usar 2 y 3 (3 me parece más simple) le permite anteponer texto a muchos archivos a la vez.
Felix

44
@Kira: Los 1medios hacen el siguiente comando solo en la línea uno del archivo y el icomando es insertar. Mire en la página del manual debajo de la sección "Direcciones" y en la sección "Comandos de cero o una dirección".
Dennis Williamson

73

Una opción más simple en mi opinión es:

echo -e "task goes here\n$(cat todo.txt)" > todo.txt

Esto funciona porque el comando dentro de $(...)se ejecuta antes de todo.txtsobrescribirse con> todo.txt

Si bien las otras respuestas funcionan bien, encuentro que esto es mucho más fácil de recordar porque uso echo y cat todos los días.

EDITAR: Esta solución es una muy mala idea si hay barras invertidas todo.txt, porque gracias a la -ebandera echo las interpretará. Otra forma mucho más fácil de obtener nuevas líneas en la cadena de prefacio es ...

echo "task goes here
$(cat todo.txt)" > todo.txt

... simplemente para usar nuevas líneas. Claro, ya no es una sola línea, pero de manera realista tampoco era una sola línea antes. Si está haciendo esto dentro de un script y le preocupa la sangría (p. Ej., Está ejecutando esto dentro de una función), existen algunas soluciones alternativas para que esto se ajuste bien, incluidos, entre otros:

(echo 'task goes here' && cat todo.txt) > todo.txt
echo 'task goes here'$'\n'"$(cat todo.txt)" > todo.txt

Además, si le importa si se agrega una nueva línea al final de todo.txt, no los use. Bueno, excepto el penúltimo. Eso no se mete con el final.


1
No obtengo $ (...) ejecutado en absoluto.
SCL

2
Eso podría funcionar mejor (o en absoluto) con comillas dobles en lugar de simples ...
phaphink

55
¿No -econvertirá también las secuencias de escape dentro de todo.txt?
mk12

2
Soluciones provisionales rendimiento -> cat: <nombre de archivo de destino>: el archivo de entrada es el archivo de salida ...
ingyhere

printf sería mucho más consistente en todas las plataformas y, en general, debería funcionar más suavemente que echo -e
Peter Berg

28

El moreutilstener una buena herramienta llamada sponge:

echo "task goes here" | cat - todo.txt | sponge todo.txt

"Absorberá" STDIN y luego escribirá en el archivo, lo que significa que no tiene que preocuparse por los archivos temporales y moverlos.

Puede obtener moreutilsmuchas distribuciones de Linux, a través apt-get install moreutilso en OS X usando Homebrew , con brew install moreutils.


Yo iría por (echo 'ble'; cat todo.txt):-)
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

11

Puede usar Vim en modo Ex:

ex -s -c '1i|task goes here' -c x todo.txt
  1. 1 seleccione primera línea

  2. i insertar

  3. x guardar y cerrar


5

Puede crear un nuevo archivo temporal.

echo "new task" > new_todo.txt
cat todo.txt >> new_todo.txt
rm todo.txt
mv new_todo.txt todo.txt

También puedes usar sedo awk. Pero básicamente sucede lo mismo.


1
Digamos que no tiene espacio en el disco para que eso new_todo.txtse escriba solo parcialmente. Su solución parece perder el archivo original.
NPE

¿Quién se queda sin espacio en disco? ;-) Es solo un ejemplo simple.
Keith

2
@Keith Alguien trabajando en una VM que no esperaba necesitar una unidad virtual particularmente grande. O alguien moviendo un archivo grande. En cualquier caso, el argumento real en contra de esto son los permisos de directorio; Si no tiene permiso para crear nuevos archivos en el directorio dado, el único comando que se ejecutará con éxito en su secuencia de comandos es el rmdel archivo original.
Parthian Shot

3

Si el archivo de texto es lo suficientemente pequeño como para caber en la memoria, no tiene que crear un archivo temporal para reemplazarlo. Puede cargarlo todo en la memoria y volver a escribirlo en el archivo.

echo "$(echo 'task goes here' | cat - todo.txt)" > todo.txt

Es imposible agregar líneas al comienzo del archivo sin sobreescribir todo el archivo.


Solo para hacer la pregunta obvia: ¿Dónde está el límite de caracteres de las variables de shell?
nixda

Que yo sepa, solo está limitado por la cantidad de memoria disponible. He llenado variables de más de 100 MB en la memoria. text=$(cat file). Sin embargo, tenga cuidado de usar solo texto, porque las variables de shell no son binarias. Mywiki.wooledge.org/BashFAQ/058
Rucent88

2

No puede insertar contenido al comienzo de un archivo. Lo único que puede hacer es reemplazar el contenido existente o agregar bytes después del final actual del archivo.

Cualquier solución a su pregunta requiere que se cree un archivo temporal (o búfer) (en la memoria o en el disco) que eventualmente sobrescribirá el archivo original.

Tenga cuidado de no perder datos conservando el archivo original mientras crea el nuevo, en caso de que el sistema de archivos esté lleno durante el proceso. p.ej:

cat <(echo task go there) todo.txt > todo.txt.new && mv todo.txt.new todo.txt

Los downvoters pueden explicar su motivación. Ninguna de las respuestas restantes, incluida la aceptada, contradice nada en mi respuesta.
jlliagre

Esto es difícil de analizar ya que los <...> parecen paréntesis, lo que supongo que no lo son. Un espacio entre el <y el (¿podría ayudar?
dumbledad

Esto no está funcionando para mí. echo HOME=\"/g/Users/timregan/\" | cat - 'F:\Program Files\Git\etc\profile'funciona pero cat <echo HOME=\"/g/Users/timregan/\" 'F:\Program Files\Git\etc\profile'da el error "echo: No
existe

@dumbledad Estás pensando demasiado en mi respuesta. No hay nada que puedas analizar en él. Un espacio entre el <y el (rompería la sintaxis. Pruebacat <(echo HOME=\"/g/Users/timregan/\") 'F:\Program Files\Git\etc\profile'
jlliagre


0

GitBash + Windows10 + Multline :

Aquí hay una versión que le permite usar cadenas de varias líneas .

##############################################
## This section for demo purpose only,      ##
## So you can save entire file as           ##
## whatever.sh and run it.                  ##
##                                          ##
##############################################
> MY_TARGET_FILE.txt ##Make Or Clear File
echo "[STARTER_CONTENT]" >> MY_TARGET_FILE.txt
##############################################

## Below is main code:

##################################################
TARGET_FILE_VARIABLE="MY_TARGET_FILE.txt"
ADD_TO_HEAD_VARIABLE=$(cat << "HEREDOC_HEAD_TEXT"
//|  +-------------------------------------+   |//
//|  |                                     |   |//
//|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
//|  |                                     |   |//
//|  +-------------------------------------+   |//
HEREDOC_HEAD_TEXT
)
##################################################
TAR=$TARGET_FILE_VARIABLE                       ##
TEX=$ADD_TO_HEAD_VARIABLE                       ##
echo "$TEX" | cat - $TAR > TEMP && mv TEMP $TAR ##
##################################################

## Expected contents of MY_TARGET_FILE.txt :
## //|  +-------------------------------------+   |//
## //|  |                                     |   |//
## //|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
## //|  |                                     |   |//
## //|  +-------------------------------------+   |//
## [STARTER_CONTENT]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.