¿Por qué `cat / dev / null> / var / log / messages`?

77

En esta página de ejemplo de script bash, el autor presenta este script:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

¿Por qué te gustaría cat /dev/nullalgo? No puedo entender lo que se pretende aquí (¿es como usar while TRUE; sleep 1; elihwpara {some busy program}?). Sin embargo, el autor lo llama "Nada inusual".

isomorfismos
fuente

Respuestas:

40

Por lo general, cat /dev/null > [something]cuando desea borrar el contenido del archivo y al mismo tiempo asegurarse de que no hay absolutamente ningún riesgo de interrupción del estado real del archivo. El contenido del archivo será claramente borrado por el cat /dev/nullarchivo, pero tal como existe y es conocido por el sistema de archivos en el que reside, seguirá estando allí con el mismo número de inodo, propiedad y permisos.

En el caso de un archivo de registro, podría ser que el propio archivo de registro esté marcado como "en uso" por otro proceso. Hacerlo, por ejemplo, rm /var/log/messages && touch /var/log/messagessería perjudicial para otros procesos y podría provocar que los procesos en ejecución se ahoguen. Es decir, un proceso que de alguna manera está bloqueado a un número de inodo específico conectado al archivo /var/log/messagespodría de repente entrar en pánico y decir: "¡Hey! ¡Qué pasó /var/log/messages! ”Incluso si el archivo todavía está allí. Sin mencionar posibles problemas con la propiedad y los permisos que se recrean incorrectamente.

Debido a esta incertidumbre en el uso / estado de un archivo, el uso de cat /dev/null > [something]es preferido por los administradores del sistema que desean borrar un registro pero no quieren interferir potencialmente con la operación de procesos ya existentes.

Además, en el contexto de la página que vincula al autor, se indica lo siguiente:

Aquí no hay nada inusual, solo un conjunto de comandos que podrían haberse invocado fácilmente uno por uno desde la línea de comandos en la consola o en una ventana de terminal. Las ventajas de colocar los comandos en un script van mucho más allá de no tener que volver a escribirlos una y otra vez.

Entonces, "nada inusual" que el autor menciona es con respecto al concepto completo de lo que es ese script bash específico: es solo un conjunto de comandos simples que se pueden ejecutar fácilmente desde la línea de comandos pero se colocan en un archivo de texto para evite tener que volver a escribirlos una y otra vez.

JakeGould
fuente
10
@jlliagre Lo único que se "mantiene vivo" es el contexto de la pregunta que se centra en por qué el autor original haría eso. Si le apasiona disipar el "mito", publique una respuesta que brinde contexto para el método de codificación del autor original, así como una perspectiva de por qué cree que puede ser reemplazado por otros métodos.
JakeGould
77
La respuesta de @jlliagre Cyrus no aborda la pregunta central de por qué el autor original habría utilizado ese método ni el razonamiento detrás de él. El tutorial mencionado es bastante antiguo y razonablemente aceptado. No es incorrecto ni perpetúa una supuesta "leyenda urbana". Más bien es la forma en que una persona codifica frente a la forma en que otra persona codifica. Tan sencillo como eso. Es un problema de estilo que no tiene un impacto negativo en la fiabilidad o el rendimiento.
JakeGould
3
truncate -s 0haría lo mismo y sería menos idiomático. Sin embargo, los programadores de shell son un grupo conservador y uno puede encontrar sistemas lo suficientemente antiguos o locos como para carecer de ese comando.
Schwern
55
@skift cat /dev/null > /foo/bartrunca el archivo; echo "" > /foo/barlo trunca y luego escribe un solo carácter de nueva línea.
David
2
Otra ventaja de este método sobre rm & touch es que se mantienen la propiedad y los permisos.
jjmontes
121

¿Por qué querrías cat / dev / null en algo?

Hará eso para truncar el contenido de un archivo mientras mantiene el inodo intacto. Todos los programas que tienen ese archivo abierto para leer o escribir no se verían afectados fuera del hecho de que el tamaño del archivo se restablecería a cero.

Una alternativa falsa que a menudo se encuentra es eliminar el archivo y luego volver a crearlo:

rm file
touch file

o similar:

mv file file.old
gzip file.old
touch file

El problema es que estos métodos no evitan que el archivo antiguo se mantenga escrito por cualquier proceso que tenga el archivo eliminado abierto en el momento de la eliminación. La razón por la cual está bajo los sistemas de archivos Unix, cuando elimina un archivo, solo desvincula su nombre (ruta) de su contenido (inodo). El inodo se mantiene vivo siempre que haya procesos que lo tengan abierto para leer o escribir.

Esto lleva a varios efectos negativos: los registros escritos después de la eliminación del archivo se pierden, ya que no hay una forma directa / portátil de abrir un archivo eliminado. Mientras un proceso escriba en el archivo eliminado, su contenido seguirá utilizando espacio en el sistema de archivos. Eso significa que si elimina / crea el archivo porque estaba llenando su disco, el disco permanece lleno. Una forma de solucionar este último problema es reiniciar los procesos del registrador, pero es posible que no desee hacerlo para los servicios críticos y los registros intermedios se perderían definitivamente. También hay efectos secundarios debido al hecho de que el archivo que cree podría no tener los mismos permisos, propietario y grupo que el original. Esto, por ejemplo, podría evitar que un analizador de registros lea el archivo recién creado o, lo que es peor, evitar que el proceso de registro escriba sus propios registros.

El primer método, cat /dev/null > filelograr el objetivo correctamente , sin embargo, a pesar de una tenaz leyenda urbana, su cat /dev/nullparte no hace absolutamente nada útil. Abre un pseudo archivo que está vacío por diseño, no puede leer nada de él y finalmente se cierra. El uso de este comando es un desperdicio de pulsaciones de teclas, bytes, llamadas al sistema y ciclos de la CPU, y puede ser reemplazado sin ningún cambio funcional por el comando no-operablemente más rápido :o incluso, con la mayoría de los shells, por ningún comando.

Déjame probar una metáfora para explicar lo inútil que cat /dev/nulles. Digamos que su objetivo es vaciar un vaso.

  • Primero eliminas cualquier líquido de él. Eso es suficiente y es precisamente lo que hace ( > file) dado el hecho de que las redirecciones siempre se procesan primero.

  • Luego, elige una botella vacía ( /dev/null) y la vierte en el vaso vacío ( cat). Este es el paso inútil ...

Si lee su documento vinculado hasta el final, puede notar los comentarios en esta línea de la versión mejorada del script:

    cat / dev / null> wtmp #   ':> wtmp' y '> wtmp' tienen el mismo efecto.

Tienen de hecho; lástima cat /dev/nullse mantuvo en el código.

Eso significa que el siguiente código funcionará con todos los shells comunes (ambos cshy shfamilias):

cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."

y esto va a trabajar con todas las conchas utilizando la sintaxis Bourne, como ash, bash, ksh, zshy los gustos:

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

Sin embargo, tenga en cuenta que con los antiguos shells Bourne anteriores a POSIX, cualquiera de estos comandos, incluido el cat /dev/nulltruncado, no truncará un archivo si luego lo escribe un script de shell que aún se está ejecutando. En lugar de un archivo de cero bytes, sería un archivo disperso con su tamaño sin cambios. Lo mismo sucedería si el archivo está escrito por un proceso que busca la posición que cree que es la actual antes de escribir.

Tenga en cuenta también que algunas soluciones alternativas a menudo sugeridas para truncar un archivo tienen fallas.

  • Los dos siguientes simplemente no hacen el trabajo. El archivo resultante no está vacío, pero contiene una línea vacía. Esto rompería los archivos de registro como wtmpese que almacenan registros de ancho fijo.

    echo > file
    echo "" > file
  • El siguiente basado en una shopción BSD no es portátil, POSIX no especifica ninguna opción permitida para echo, por lo que puede terminar con un archivo que contiene una línea con " -n":

    echo -n > file
  • Ese tampoco es portátil usando una shsecuencia de escape del Sistema V. Algunos shells crearán un archivo que contiene una línea con " \c":

    echo "\c" > file
  • Ese usa un comando diseñado para hacer el trabajo. El problema que está utilizando truncateno es portátil porque este comando, que no está especificado por POSIX, puede faltar en un sistema Unix / Linux.

    truncate -s 0

Finalmente, aquí hay un par de alternativas que son portátiles y que harán el trabajo correctamente:

  • Imprimir explícitamente una cadena vacía en el archivo:

    printf "" > file
  • Usando el truecomando que es estrictamente equivalente al no operativo, :aunque más legible:

    true > file
jlliagre
fuente
1
@JonathanLeffler Creo que es parte de todas las cshimplementaciones actuales , aunque no está necesariamente documentado. De la csh página del manual de Solaris : Null command. This command is interpreted, but performs no action.. No encontré ninguna mención de lo mismo ni en la tcshpágina del manual ni en las BSD originales csh, pero esta sintaxis podría haber funcionado siempre.
jlliagre
66
Una razón para escribir cat /dev/nulles hacer explícitas tus intenciones.
Davidmh
1
@Davidmh Eso sería sensato, pero su declaración no resiste las verificaciones de hechos. He observado esta expresión idiota durante probablemente un par de décadas. Cuando tuve la oportunidad de preguntarle al autor el razonamiento detrás de esto, siempre obtuve teorías erróneas sobre el uso de /dev/nullser una manera eficiente de inyectar cero bytes, de todos modos una más confiable que usar :o nada. En esta misma página, la respuesta de Cyrus, que era conciso pero directo al grano, tenía cero votos, mientras que la de JakeGould que cuestionaba el hecho cat /dev/nullera un no operativo (ver nuestros comentarios) ya tenía al menos cuatro votos.
jlliagre
2
@jlliagre mi conocimiento del shell es bastante básico, así que quizás no soy el mejor objetivo de población; pero un desnudo >o :no está claro. Estoy de acuerdo en que es una pena que los mitos se hayan propagado debido a su uso.
Davidmh
44
@Davidmh Si realmente desea algo explícito antes de la redirección, recomendaría printf "" > fileque sea portátil (POSIX) y liviano, tan a menudo implementado como un shell incorporado.
jlliagre
6

Es una forma engorrosa de llevar el archivo a tamaño cero.

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
Ciro
fuente
Esta sintaxis no funcionará en todos los shell.
reinierpost
2
Correcto. La pregunta solo está etiquetada con "bash".
Cyrus
@reinierpost Funcionará en todos los proyectiles de estilo Bourne, ¿no? No nos preocupemos por eso csh.
Barmar
: > messagesTambién funciona. :o trueson las opciones más obvias para los comandos que no imprimen nada y devuelven verdadero.
Peter Cordes
-3

Para truncar un archivo abierto. Esto es equivalente y más comprensible:

echo -n > /var/log/messages

(Agregado -n para evitar la nueva línea)

bbaassssiiee
fuente
3
De hecho, esto es más comprensible pero desafortunadamente no es equivalente. Incluso romperá funcionalidades como en el wtmpcaso. Ver mi respuesta actualizada.
jlliagre
echo -n evita la nueva línea.
bbaassssiiee
66
De hecho, si está seguro de usar bash, de -nlo contrario no se garantiza que funcione en todos los shells Bourne.
jlliagre