Advertencia sobre '>'
Principiantes de Unix que acaban de aprender sobre la redirección de E / S ( <
y >
) a menudo prueban cosas como
comando ... archivo_entrada > the_same_file
o
comando ... < archivo > the_same_file
o, casi equivalentemente,
archivo de gato | comando ...> the_same_file
( grep
, sed
, cut
, sort
, Y spell
son ejemplos de comandos que las personas se ven tentados a utilizar en construcciones como éstas.) Los usuarios son sorprendidos al descubrir que estos escenarios resultan en el archivo se vacíe.
Un matiz que no parece mencionarse en la otra respuesta se puede encontrar al acecho en la primera oración de la sección Redirección de bash (1) :
Antes de ejecutar un comando, su entrada y salida se pueden redirigir
utilizando una notación especial interpretada por el shell.
Las primeras cinco palabras deben estar en negrita, cursiva, subrayadas, ampliadas, parpadeantes, de color rojo y marcadas con un icono, para enfatizar el hecho de que el shell realiza las redirecciones solicitadas
antes de ejecutar el comando . Y recuerda también
La redirección de la salida hace que el archivo ... se abra para escribir ... Si el archivo no existe, se crea; si existe, se trunca a tamaño cero.
Entonces, en este ejemplo:
sort roster > roster
el shell abre el roster
archivo para escribir, truncándolo (es decir, descartando todo su contenido), antes de que el sort
programa comience a ejecutarse. Naturalmente, no se puede hacer nada para recuperar los datos.
Uno podría esperar ingenuamente que
tr "[:upper:]" "[:lower:]" < poem > poem
podría ser mejor. Debido a que el shell maneja las redirecciones de izquierda a derecha, se abre poem
para leer (para tr
la entrada estándar) antes de abrirlo para escribir (para la salida estándar). Pero no ayuda. Aunque esta secuencia de operaciones produce dos identificadores de archivo, ambos apuntan al mismo archivo. Cuando el shell abre el archivo para leerlo, el contenido todavía está allí, pero aún así se bloquea antes de que se ejecute el programa.
Entonces, ¿qué hacer al respecto?
Las soluciones incluyen:
Compruebe si el programa que está ejecutando tiene su propia capacidad interna para especificar a dónde va la salida. Esto a menudo se indica mediante una -o
(o --output=
) ficha. En particular,
sort roster -o roster
es más o menos equivalente a
sort roster > roster
excepto, en el primer caso, el sort
programa abre el archivo de salida. Y es suficiente para no abrir el archivo de salida inteligente hasta que después de haber leído todo el archivo (s) de entrada.
Del mismo modo, al menos algunas versiones de sed
tienen un -i
(edición i n Place) opción que se puede utilizar para escribir el resultado de vuelta al archivo de entrada (de nuevo, después de todo la entrada de haber sido leído). Editores como ed
/ ex
, emacs
, pico
y vi
/ vim
permiten al usuario editar un archivo de texto y guardar el texto editado en el archivo original. Tenga en cuenta que ed
(al menos) puede usarse de forma no interactiva.
vi
Tiene una característica relacionada. Si escribe , escribirá el contenido del búfer de edición , leerá el resultado y lo insertará en el búfer (reemplazando el contenido original).:%!command
Entercommand
Simple pero efectivo:
comando ... archivo_entrada > temp_file && mv temp_file archivo_entrada
Esto tiene el inconveniente de que, si input_file
es un enlace, (probablemente) será reemplazado por un archivo separado. Además, el nuevo archivo será de su propiedad, con protecciones predeterminadas. En particular, esto conlleva el riesgo de que el archivo termine siendo legible en todo el mundo, incluso si el original input_file
no lo fuera.
Variaciones:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
que todavía (potencialmente) dejará el temp_file
mundo legible. Aun mejor:
cp input_file temp_file && command … temp_file > input_file && rm temp_file
Éstos preservan el estado del enlace, el propietario y el modo (protección) del archivo, potencialmente a costa del doble de E / S. (Es posible que necesite usar una opción como -a
o -p
en cp
contarla para preservar atributos.)
command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(dividido en líneas separadas solo para facilitar la lectura) Esto conserva el modo del archivo (y, si es root, el propietario), pero lo hace suyo (si no es root), y lo convierte en un nuevo, archivo separado
Este blog
(edición "in situ" de archivos) sugiere y explica
{rm input_file && command ...> input_file ; } < input_file
Esto requiere que command
se pueda procesar la entrada estándar (pero casi todos los filtros pueden). El propio blog llama a esto un riesgo arriesgado y desalienta su uso. Y esto también creará un archivo nuevo y separado (no vinculado a nada), propiedad de usted y con permisos predeterminados.
El paquete moreutils tiene un comando llamado sponge
:
comando ... input_file | esponja the_same_file
Vea esta respuesta para más información.
Aquí hay algo que me sorprendió por completo:
syntaxerror dice :
[La mayoría de estas soluciones] fallará en un sistema de archivos de solo lectura, donde “solo lectura” significa que $HOME
se podrá escribir, pero /tmp
será de solo lectura (por defecto). Por ejemplo, si tiene Ubuntu y ha arrancado en la Consola de recuperación, este suele ser el caso. Además, el operador de documento aquí <<<
tampoco funcionará allí, ya que requiere /tmp
ser leído / escrito
porque también escribirá un archivo temporal allí.
(cf. esta pregunta incluye una strace
'd salida)
Lo siguiente puede funcionar en ese caso:
¿Entonces, cuál era la pregunta?
Este ha sido un tema popular en U&L; se aborda en las siguientes preguntas:
... y eso sin contar Super User o Ask Ubuntu. He incorporado mucha de la información de las respuestas a las preguntas anteriores aquí en esta respuesta, pero no todas. (Es decir, para obtener más información, lea las preguntas mencionadas anteriormente y sus respuestas).
PD tiene ninguna afiliación con el blog que he citado más arriba.