¿Hay un comando Unix para anteponer algunos datos de cadena a un archivo de texto?
Algo como:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
¿Hay un comando Unix para anteponer algunos datos de cadena a un archivo de texto?
Algo como:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Respuestas:
sed -i.old '1s;^;to be prepended;' inFile
-i
escribe el cambio en su lugar y realiza una copia de seguridad si se proporciona alguna extensión. (En este caso .old
)1s;^;to be prepended;
sustituye el comienzo de la primera línea por la cadena de reemplazo dada, utilizando ;
como delimitador de comando.\n
después de anteponer; dependiendo de sus necesidades Solución ordenada
inFile
incluir los directorios en su ruta?
\n
. Debería haber leído los comentarios primero. Maldición.
'1s;^;my-prepended-line\;\n;'
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';
y esto se confunde al convertir el \t
y \n
.
echo "to be prepended"$'\n'"$(cat text.txt)"
Me sorprende que nadie haya mencionado esto.
cat <(echo "before") text.txt > newfile.txt
lo cual es posiblemente más natural que la respuesta aceptada (imprimir algo y colocarlo en un comando de sustitución es lexicográficamente contra-intuitivo).
... y secuestrando lo que Ryan dijo anteriormente, con sponge
usted no necesita un archivo temporal:
sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt
EDITAR: Parece que esto no funciona en Bourne Shell /bin/sh
Usando una cadena aquí <<<
, puede hacer:
<<< "to be prepended" < text.txt | sponge text.txt
<<(echo "to be prepended") < text.txt
y <<< "to be prepended" < text.txt
construcciones no funcionan en bash; requieren zsh.
Esta es una posibilidad:
(echo "to be prepended"; cat text.txt) > newfile.txt
Probablemente no pueda moverse fácilmente por un archivo intermedio.
Alternativas (pueden ser engorrosas con el escape de la carcasa):
sed -i '0,/^/s//to be prepended/' text.txt
cat <(echo "to be prepended") text.txt > newfile.txt
. Ahora que lo pienso, no estoy seguro de que el mío esté relacionado, así que publicaré una respuesta por separado.
Esto funcionará para formar la salida. El - significa entrada estándar, que se proporciona a través de la tubería desde el eco.
echo -e "to be prepended \n another line" | cat - text.txt
Para reescribir el archivo, se requiere un archivo temporal ya que no se puede volver a conectar al archivo de entrada.
echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
text.txt
como se solicitó, sino que lo muestra en stdout. La salida podría canalizarse a un archivo diferente si eso funciona para el OP
Prefiero la respuesta de Adam
Podemos hacer que sea más fácil usar esponja . Ahora no necesitamos crear un archivo temporal y renombrarlo por
echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
Nota:
Hacerlo puede tener efectos secundarios inesperados, que pueden reemplazar un enlace simbólico con un archivo normal, terminar con diferentes permisos en el archivo y cambiar la fecha de creación (nacimiento) del archivo.
sed -i
, como en la respuesta del príncipe John Wesley , intenta al menos restaurar los permisos originales, pero también se aplican las otras limitaciones.
Aquí hay una alternativa simple que usa un archivo temporal (evita leer todo el archivo de entrada en la memoria como lo hace la solución de shime ):
{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt
Usar un comando de grupo ( { ...; ...; }
) es un poco más eficiente que usar un subshell ( (...; ...)
), como en la solución de 0xC0000022L .
Las ventajas son:
Es fácil controlar si el nuevo texto debe anteponerse directamente a la primera línea o si debe insertarse como nueva (s) línea (s) (simplemente agregue \n
el printf
argumento).
A diferencia de la sed
solución, funciona si el archivo de entrada está vacío ( 0
bytes).
La sed
solución se puede simplificar si la intención es anteponer una o más líneas enteras al contenido existente (suponiendo que el archivo de entrada no esté vacío):
sed
La i
función de inserta líneas enteras:
Con GNU sed
:
# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile
Una variante portátil que también funciona con macOS / BSD sed
:
# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile
Tenga en cuenta que la nueva línea literal después de la \
es obligatoria.
Usando la venerable ed
utilidad POSIX :
Nota:
ed
invariablemente lee el archivo de entrada como un todo en la memoria primero.Para anteponer directamente a la primera línea (como con sed
, esto no funcionará si el archivo de entrada está completamente vacío ( 0
bytes)):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-s
ed
mensajes de estado suprimidos .ed
como un documento de varias líneas aquí ( <<EOF\n...\nEOF
), es decir, a través de stdin ; de manera predeterminada, la expansión de cadenas se realiza en dichos documentos (las variables de shell se interpolan); cita el delimitador de apertura para suprimir eso (por ejemplo, <<'EOF'
).1
convierte la primera línea en la línea actuals
realiza una sustitución de cadena basada en expresiones regulares en la línea actual, como en sed
; puede incluir nuevas líneas literales en el texto de sustitución, pero deben ser \
-escapeadas.w
vuelve a escribir el resultado en el archivo de entrada (para probar, reemplace w
con ,p
para imprimir solo el resultado, sin modificar el archivo de entrada).Para anteponer una o más líneas enteras :
Al igual que con sed
, la i
función agrega invariablemente una nueva línea final al texto que se va a insertar.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 i
hace 0
(el comienzo del archivo) la línea actual y comienza el modo de inserción ( i
); tenga en cuenta que los números de línea están 1
basados en otra cosa ..
en su propia línea.Probablemente no tenga nada incorporado, pero podría escribir el suyo con bastante facilidad, así:
#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"
Algo así al menos ...
$$
embargo, el uso es insuficiente para el código de producción (ataque de enlace simbólico de Google); pero ciertamente es mejor que un nombre de archivo estático.
mktemp
En algunas circunstancias, el texto antepuesto puede estar disponible solo desde stdin. Entonces esta combinación funcionará.
echo "to be prepended" | cat - text.txt | tee text.txt
Si desea omitir la tee
salida, agregue > /dev/null
.
tee
no golpee text.txt
antes de cat
poder leerlo? Creo que no, lo que haría que esta solución fuera peligrosa para la salud del archivo.
lenA=1000000; yes a | head -c $lenA > a.txt; lenB=10000; b=$(yes b | head -c $lenB); echo "$b" | cat - a.txt | tee a.txt > /dev/null
. Si lenA
es 1000000 (archivo de 1Mb) y lenB
es 10000 (antecedente de texto de 10Kb), el archivo "a.txt" se sobrescribe con 20Kb de letras "b". Esto está totalmente roto. Ahora, si usa texto de 1Mb a.txt y 1Mb para anteponer, tee
entra en un bucle que genera un archivo de 7Gb +, tuve que detener el comando. Por lo tanto, es obvio que el resultado es impredecible para tamaños grandes. No tengo información sobre si debería funcionar en tamaños pequeños.
Solución:
printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt
Tenga en cuenta que esto es seguro en todo tipo de entradas, porque no hay expansiones. Por ejemplo, si desea anteponer !@#$%^&*()ugly text\n\t\n
, simplemente funcionará:
printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt
La última parte que queda por considerar es la eliminación de espacios en blanco al final del archivo durante la sustitución del comando "$(cat file.txt)"
. Todas las soluciones para esto son relativamente complejas. Si desea conservar las nuevas líneas al final del archivo.txt, consulte esto: https://stackoverflow.com/a/22607352/1091436
file.txt
es más grande de lo que se puede incluir en la lista de argumentos printf
.
Otra forma de usar sed
:
sed -i.old '1 {i to be prepended
}' inFile
Si la línea a anteponer es multilínea:
sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
sed -i '1ito be prepended' inFile
, o solo está permitido para GNU sed?
sed
, el i
comando va seguido de una barra diagonal inversa y una nueva línea, y cada línea de entrada, excepto la última, también termina con una barra diagonal inversa. GNU sed
permite shorthands a lo largo de las líneas que usted pregunta, pero solo GNU sed
lo hace '.
Según lo probado en Bash (en Ubuntu), si comienza con un archivo de prueba a través de;
echo "Original Line" > test_file.txt
puedes ejecutar;
echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt
o, si la versión de bash es demasiado antigua para $ (), puede usar backticks;
echo "`echo "New Line"; cat test_file.txt`" > test_file.txt
y reciba los siguientes contenidos de "test_file.txt";
New Line
Original Line
Sin archivo intermediario, solo bash / echo.
Otra solución bastante sencilla es:
$ echo -e "string\n" $(cat file)
cat
expansión del parámetro entre comillas dobles es una muy buena razón para un voto negativo . Este código está dividiendo el contenido del archivo en palabras y pasando cada una de esas palabras como un argumento separado para echo
. Pierde los límites del argumento original, pierde líneas nuevas / pestañas / etc., y las cadenas como \t
y \n
en el texto original se reemplazan con pestañas y líneas nuevas en lugar de mantenerse como estaban.
Si te gusta vi / vim, este puede ser más tu estilo.
printf '0i\n%s\n.\nwq\n' prepend-text | ed file
Recomiendo definir una función y luego importarla y usarla cuando sea necesario.
prepend_to_file() {
file=$1
text=$2
if ! [[ -f $file ]] then
touch $file
fi
echo "$text" | cat - $file > $file.new
mv -f $file.new $file
}
Luego úsalo así:
prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"
El contenido de su archivo será:
This is second
This is first
Estoy a punto de utilizar este enfoque para implementar un actualizador de registro de cambios.