¿Hay otra forma simple de agregar una línea al final del archivo que no sea `>>`?

21

Recientemente estoy haciendo eco de frases cortas a un tree_holearchivo.

Estaba usando echo 'something' >> tree_holepara hacer este trabajo.

Pero siempre me preocupó qué pasaría si ingresaba mal en >lugar de hacerlo >>, ya que lo hacía a menudo.

Así que hice una función de bash global propia en bashrc:

function th { echo "$1" >> /Users/zen1/zen/pythonstudy/tree_hole; }
export -f th

Pero me pregunto si hay otra forma simple de agregar líneas al final de un archivo. Porque es posible que necesite usar eso a menudo en otras ocasiones.

¿Hay alguna?

zen
fuente
99
¿No olvidará que está utilizando la solución cada vez que ingresa>? Una vez tuve un alias rm="rm -i"y en otro entorno escribí rm *esperando las preguntas de confirmación. ¡Estás aprendiendo hábitos peligrosos!
Walter A
99
@WalterA er, su "solución" no le permite escribir> en lugar de >>, simplemente ejecuta "th some_sentence", que no hace nada si el alias no está definido.
Random832
1
@ Ranom832 correcto para su solución alternativa. La advertencia es para una "solución" como noclobber. Cuando usa algo como noclobber en su caparazón normal, puede usar> cuando es root temporal y quiere agregar algo.
Walter A
77
@ Random832 & WalterA Normalmente no digo nada sobre esto cuando lo veo, pero pensé que de vez en cuando podría ser útil un aviso amistoso. El perfil de usuario de Zen no tiene muchos detalles, por lo que no estoy seguro si realmente sabe que su "solución" es la forma correcta. Tal vez deberías decir su "solución" o la "solución" del OP . Quizás conozca a Zen personalmente y, por lo tanto, sepa que el suyo es correcto, en cuyo caso, perdone el ruido. No es gran cosa, solo lo menciono porque sé que no lo habría apreciado mucho si hubieras usado ese formulario para hablar de mí.
Celada
1
@ Zen, usted escribió que está preocupado por ingresar incorrectamente> en lugar de >>. El plan de Celada eliminará los riesgos en su entorno y es una buena solución para usted. Cuando está ayudando a su vecino (que no tiene noclobber o está usando ksh) y pierde su atención por uno o dos caracteres>, puede sobrescribir accidentalmente uno de sus archivos. Así que cada vez que reciba la advertencia de noclobber en su propio entorno, gracias a Dios o Celada, díganse a sí mismos: ¡Ohh, tengan cuidado, por favor !, sacudan la cabeza y esperen dos segundos.
Walter A

Respuestas:

47

Establezca la noclobberopción del shell :

bash-3.2$ set -o noclobber
bash-3.2$ echo hello >foo
bash-3.2$ echo hello >foo
bash: foo: cannot overwrite existing file
bash-3.2$ 
Celada
fuente
3
Esta es la respuesta definitiva. Tenga en cuenta que aún puede sobrescribir el archivo si lo fuerza >|. zshhabilita este comportamiento por defecto.
orion
1
@orion ¿Cómo se activa / desactiva en zsh? No recuerdo deshabilitarlo explícitamente, pero la sobrescritura funciona bien en mi zsh.
Muru
2
Es setopt noclobbery setopt clobber. Parece que no es exactamente "predeterminado", depende de los archivos de configuración que se envían con su distribución.
orion
@muru debería funcionar set [+-]Cpara cualquier shell moderno
mikeserv
3
@Zen set +o noclobberen bash, o set +C.
Ruslan
7

Si le preocupa su archivo será dañada por el >operador puede cambiar su atributo de archivo de sólo-añadir:
En ext2 / ext3 / ext4 sistema de archivos: chattr +a file.txt
En XFS sistema de archivos:echo chattr +a | xfs_io file.txt

Y si desea una función, ya hice una función para mí (la usé en el archivo de servicio para registrar salidas), puede cambiarla para su propósito:

# This function redirect logs to file or terminal or both!
#@ USAGE: log option data
# To the file     -f file
# To the terminal -t
function log(){
        read -r data       # Read data from pipe line

        [[ -z ${indata} ]] && return 1    # Return 1 if data is null

        # Log to /var/log/messages
        logger -i -t SOFTWARE ${data}

        # While loop for traveling on the arguments
        while [[ ! -z "$*" ]]; do
                case "$1" in
                        -t)
                                # Writting data to the terminal
                                printf "%s\n" "${data}"
                                ;;
                        -f) 
                                # Writting (appending) data to given log file address
                                fileadd=$2
                                printf "%s %s\n" "[$(date +"%D %T")] ${data}" >> ${fileadd}
                                ;;
                        *)
                                ;;
                esac
                shift           # Shifting arguments
        done
}
Sepahrad Salour
fuente
2
Hay algunos problemas con este script. 1) Por lo general, debe poner comillas dobles alrededor de las expansiones de parámetros (cosas que comienzan con a $) para evitar el engorde, la división de palabras y los problemas de espacios en blanco relacionados. La aplicación ShellCheck en línea puede detectar este y otros problemas en los scripts de bash. En una nota relacionada "$@"es mucho más seguro que $*.
PM 2Ring
3
2) Normalmente debería llamar al readcomando con la -ropción de evitar que las barras invertidas en la entrada escapen del siguiente carácter. 3) Es habitual en los scripts de bash utilizar minúsculas para los nombres de variables de script, ya que ALL MAYÚSCULAS se usa para las variables del sistema. Entonces, si usa mayúsculas para sus propias variables, confundirá a las personas que leen su código, y puede accidentalmente golpear una variable del sistema que desea usar más adelante en el script. Y si obtiene el script, bloqueará las variables para los comandos posteriores.
PM 2Ring
3
4) echoes útil para imprimir cadenas fijas, pero puede hacer cosas inesperadas con datos arbitrarios, especialmente en sistemas GNU. Es mucho más seguro de usar printf. Consulte unix.stackexchange.com/questions/65803/… para obtener más información, especialmente la respuesta de Stéphane Chazelas.
PM 2Ring
3
@PM 2Ring, hoy aprendí muchas cosas de ti, muchas gracias ... las arreglaré lo antes posible.
Sepahrad Salour
1
Buen trabajo, Sepahrad!
PM 2Ring
3

Usar teecon la opción de agregar:

foo | tee -a some-file
# or
tee -a some-file <<EOF
blah blah
EOF
# or 
tee -a some-file <<<"blah blah"
muru
fuente
55
Buena idea, +1, pero imagino que si el OP está preocupado por olvidar un >personaje, ¡entonces podrían estar preocupados por olvidar la -aopción!
Celada
@Celada, supongo que sí (pero supongo que es más probable que ocurra un error tipográfico por faltar una pulsación de tecla en un conjunto de pulsaciones repetidas que olvidar una opción).
Muru
0

muchos programas que pueden abrir archivos para sobrescribirlos pueden abrirlos para agregarlos, por ejemplo, gnu dd.

dd conv=notrunc oflag=append of=file

puede leer stdin o un archivo nombrado en el if= parámetro add 2>/dev/nullpara suprimir el recuento de bytes.

Jasen
fuente
3
Es una buena idea ™ para probar el código antes de la publicación como respuesta ...
PM 2Ring
1
Recomendar ddes una mala idea. ddno escribe de manera confiable su entrada en su salida , no cuando uno de ellos no es un archivo normal o un dispositivo de bloque
Gilles 'SO- deja de ser malo'
@gilles, está tergiversando la información en ese enlace, cuando no se especifica el conteo dd copiará todos los datos disponibles, al igual que cat.
Jasen
-1

Me gustaría usar un sed(incluso con copia de seguridad - ver extensión después -i):

sed -i.bak '$ a\something' /Users/zen1/zen/pythonstudy/tree_hole
Costas
fuente
¿Por qué no me sorprende? Eres un maníaco sed, Costas. :) (Eso es un cumplido, por cierto)
PM 2Ring
@ PM2Ring Sí, soy muy peligroso! : P
Costas
Por supuesto, la forma en que funciona es hacer una copia del archivo, agregar el nuevo texto al final, luego eliminar el archivo original y cambiar el nombre de la copia al nombre original. Esto (1) no funciona si no tiene acceso de escritura al directorio, (2) rompe enlaces y (3) es costoso en recursos si el archivo es grande. Es curioso que hayas mencionado la palabra "peligroso".
G-Man dice 'Reincorporar a Monica' el
-1

Siempre puede buscar a través del archivo de otras maneras ...

seq 10000000 >f
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
{ wc -l >&2; echo new line\!; } <>f >&0; \
wc -l f; tail f

... esa secuencia de aspecto extraño se imprime:

10000000
10000001
10000002
10000003
10000004
10000005 f
9999996
9999997
9999998
9999999
10000000
new line!
new line!
new line!
new line!
new line!

Pero eso es un poco tonto.

Un ejemplo más útil podría ser:

 apnd() if    shift
        then  wc -l  >&2
              printf "$@"
        fi    <>"$1" >&0

Puedes llamarlo así:

 apnd /path/to/file          \
      "${printf_fmt_string}" \
       arbitrary list of strings

Y terminaría con un recuento de filelíneas escritas stderrjusto antes de que tenga lugar la acción de agregar.

mikeserv
fuente