En shell, ¿cómo puedo tail
crear el último archivo en un directorio?
linux
shell
shell-script
Itay Moav -Malimovka
fuente
fuente
Respuestas:
¡ No analice la salida de ls! Analizar la salida de ls es difícil y poco confiable .
Si debe hacer esto, le recomiendo usar find. Originalmente tenía aquí un ejemplo simple simplemente para darle una idea general de la solución, pero dado que esta respuesta parece algo popular, decidí revisarla para proporcionar una versión segura para copiar / pegar y usar con todas las entradas. ¿Estás sentado cómodamente? Comenzaremos con un oneliner que le dará el último archivo en el directorio actual:
No es un buen línea ahora, ¿verdad? Aquí está nuevamente como una función de shell y formateada para facilitar la lectura:
Y ahora eso como línea:
Si todo lo demás falla, puede incluir la función anterior en su
.bashrc
y considerar el problema resuelto, con una advertencia. Si solo desea hacer el trabajo, no necesita leer más.La advertencia con esto es que un nombre de archivo que termina en una o más líneas nuevas todavía no se pasará
tail
correctamente. Evitar este problema es complicado y considero que es suficiente que si se encuentra un nombre de archivo malicioso de este tipo, se produzca un comportamiento relativamente seguro de encontrar un error "No existe ese archivo" en lugar de algo más peligroso.Detalles jugosos
Para los curiosos, esta es la tediosa explicación de cómo funciona, por qué es seguro y por qué otros métodos probablemente no lo son.
Peligro, Will Robinson
En primer lugar, el único byte que es seguro para delimitar las rutas de archivos es nulo porque es el único byte universalmente prohibido en las rutas de archivos en sistemas Unix. Cuando se maneja cualquier lista de rutas de archivos, es importante utilizar solo nulo como delimitador y, al entregar incluso una sola ruta de archivo de un programa a otro, hacerlo de una manera que no ahogue bytes arbitrarios. Hay muchas formas aparentemente correctas de resolver este y otros problemas que fallan al suponer (incluso accidentalmente) que los nombres de los archivos no tendrán nuevas líneas o espacios en ellos. Ninguna de las suposiciones es segura.
Para los propósitos de hoy, el primer paso es obtener una lista de archivos delimitada por nulos fuera de búsqueda. Esto es bastante fácil si tiene un
find
soporte-print0
como GNU:Pero esta lista todavía no nos dice cuál es la más nueva, por lo que debemos incluir esa información. Elijo usar el
-printf
interruptor de find que me permite especificar qué datos aparecen en la salida. No todas las versiones defind
soporte-printf
(no es estándar) pero GNU find sí. Si se encuentra sin-printf
usted, necesitará confiar-exec stat {} \;
en qué momento debe renunciar a toda esperanza de portabilidad, yastat
que tampoco es estándar. Por ahora voy a seguir asumiendo que tienes herramientas GNU.Aquí solicito el formato printf,
%T@
que es el tiempo de modificación en segundos desde el comienzo de la época de Unix seguido de un punto y luego un número que indica fracciones de segundo. Agrego a esto otro período y luego%p
(que es la ruta completa al archivo) antes de terminar con un byte nulo.Ahora tengo
Puede ser obvio, pero por el hecho de estar completo
-maxdepth 1
evita que sefind
enumeren los contenidos de los subdirectorios y\! -type d
omite los directorios que es poco probable que deseetail
. Hasta ahora tengo archivos en el directorio actual con información de tiempo de modificación, así que ahora necesito ordenar por ese tiempo de modificación.Conseguirlo en el orden correcto
De forma predeterminada,
sort
espera que su entrada sean registros delimitados por nueva línea. Si tiene GNUsort
, puede pedirle que espere registros delimitados por nulos utilizando el-z
interruptor .; para estándarsort
no hay solución. Solo estoy interesado en ordenar por los dos primeros números (segundos y fracciones de segundo) y no quiero ordenar por el nombre real del archivo, así que digosort
dos cosas: Primero, que debería considerar el punto (.
) como un delimitador de campo y segundo, que solo debe usar los campos primero y segundo al considerar cómo ordenar los registros.En primer lugar, estoy agrupando tres opciones cortas que no tienen valor juntas;
-znr
es solo una forma concisa de decir-z -n -r
). Después de eso-t .
(el espacio es opcional) le dicesort
al carácter delimitador de campo y-k 1,2
especifica los números de campo: primero y segundo (sort
cuenta los campos de uno, no cero). Recuerde que un registro de muestra para el directorio actual se vería así:Esto significa que
sort
se verá primero1000000000
y luego0000000000
al ordenar este registro. La-n
opción le indicasort
que use la comparación numérica al comparar estos valores, porque ambos valores son números. Esto puede no ser importante ya que los números son de longitud fija pero no hace daño.El otro interruptor dado
sort
es-r
para "reversa". Por defecto, la salida de una ordenación numérica será primero los números más bajos, los-r
cambia para que enumere los números más bajos al final y los números más altos primero. Dado que estos números son marcas de tiempo más altas, significará más nuevos y esto coloca el registro más nuevo al comienzo de la lista.Solo las partes importantes
A medida que emerge la lista de rutas de archivo
sort
, ahora tiene la respuesta deseada que estamos buscando en la parte superior. Lo que queda es encontrar una manera de descartar los otros registros y eliminar la marca de tiempo. Desafortunadamente, incluso GNUhead
ytail
no aceptan interruptores para que funcionen con entradas delimitadas por nulos. En cambio, uso un bucle while como una especie de hombre pobrehead
.Primero lo desarmo
IFS
para que la lista de archivos no esté sujeta a división de palabras. A continuación, digoread
dos cosas: no interprete secuencias de escape en la entrada (-r
) y la entrada se delimita con un byte nulo (-d
); aquí la cadena vacía''
se usa para indicar "sin delimitador", también delimitado por nulo. Cada registro se leerá en la variablerecord
para que cada vez que elwhile
ciclo se repita, tenga una sola marca de tiempo y un solo nombre de archivo. Tenga en cuenta que-d
es una extensión GNU; Si solo tiene un estándar,read
esta técnica no funcionará y tendrá pocos recursos.Sabemos que la
record
variable tiene tres partes, todas delimitadas por caracteres de punto. Usando lacut
utilidad es posible extraer una parte de ellos.Aquí se pasa todo el registro hacia
printf
y desde allí canalizado acut
; en bash se podía simplificar este adicionalmente utilizando una cadena de aquí acut -d. -3f- <<<"$record"
un mejor rendimiento. Decimoscut
dos cosas: primero con-d
eso, debe un delimitador específico para identificar campos (como consort
el delimitador.
se utiliza). El segundocut
recibe instrucciones-f
para imprimir solo valores de campos específicos; la lista de campos se proporciona como un rango3-
que indica el valor del tercer campo y de todos los campos siguientes. Esto significa quecut
leerá e ignorará todo, incluido el segundo.
que encuentre en el registro, y luego imprimirá el resto, que es la parte de la ruta del archivo.Después de imprimir la ruta del archivo más reciente, no hay necesidad de continuar:
break
sale del bucle sin dejar que se mueva a la segunda ruta del archivo.Lo único que queda es ejecutarse
tail
en la ruta del archivo que devuelve esta canalización. Puede haber notado en mi ejemplo que hice esto al encerrar la tubería en una subshell; lo que quizás no haya notado es que incluí la subshell entre comillas dobles. Esto es importante porque al final, incluso con todo este esfuerzo para estar seguro para cualquier nombre de archivo, una expansión de subshell sin comillas podría romper las cosas. Una explicación más detallada está disponible si está interesado. El segundo aspecto importante pero fácil de pasar por alto para la invocacióntail
es que le proporcioné la opción--
antes de expandir el nombre del archivo. Esto instruirátail
que no se están especificando más opciones y que todo lo que sigue es un nombre de archivo, lo que hace que sea seguro manejar nombres de archivos que comienzan con-
.fuente
tail -f $(find . -type f -exec stat -f "%m {}" {} \;| sort -n | tail -n 1 | cut -d ' ' -f 2)
head
ytail
no aceptan interruptores para que funcionen con entradas delimitadas por valores nulos". Mi reemplazo parahead
:… | grep -zm <number> ""
.Si te preocupan los nombres de archivos con espacios,
fuente
Puedes usar:
La
$()
construcción inicia un sub-shell que ejecuta el comandols -1t
(enumerando todos los archivos en orden de tiempo, uno por línea) y canalizándolohead -1
para obtener la primera línea (archivo).La salida de ese comando (el archivo más reciente) se pasa a
tail
procesar.Tenga en cuenta que esto corre el riesgo de obtener un directorio si esa es la entrada de directorio más reciente creada. He usado ese truco en un alias para editar el archivo de registro más reciente (de un conjunto rotativo) en un directorio que contenía solo esos archivos de registro.
fuente
-1
es necesario, lols
hace por ti cuando está en una tubería. Comparals
yls|cat
, por ejemplo.En los sistemas POSIX, no hay forma de obtener la entrada del directorio "última creación". Cada entrada de directorio tiene
atime
,mtime
yctime
, a diferencia de Microsoft Windows,ctime
no significa CreationTime, sino "Hora del último cambio de estado".Entonces, lo mejor que puede obtener es "seguir el último archivo modificado recientemente", que se explica en las otras respuestas. Yo iría por este comando:
Tenga en cuenta las comillas alrededor del
ls
comando. Esto hace que el fragmento funcione con casi todos los nombres de archivo.fuente
Si solo desea ver el cambio de tamaño de archivo, puede usar watch.
fuente
En
zsh
:Ver: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers , aquí
m
denota el tiempo de modificaciónm[Mwhms][-|+]n
, y lo anterioro
significa que está ordenado de una manera (loO
ordena de la otra manera). Los.
medios solo archivos regulares. Dentro de los corchetes se[1]
recoge el primer elemento. Para elegir tres usos[1,3]
, para obtener el uso más antiguo[-1]
.Es bonito corto y no se usa
ls
.fuente
Probablemente hay un millón de formas de hacer esto, pero la forma en que lo haría es esta:
Los bits entre los backticks (la comilla como caracteres) se interpretan y el resultado vuelve a la cola.
fuente
Un simple:
funciona bien para mí
El problema es obtener archivos que se generan después de iniciar el comando de cola. Pero si no necesita eso (ya que todas las soluciones anteriores no le importan), el asterisco es una solución más simple, en mi opinión.
fuente
fuente
Alguien lo publicó y luego lo borró por alguna razón, pero este es el único que funciona, así que ...
fuente
ls
no es lo más inteligente ...Explicación:
fuente
fuente