En shell, ¿cómo puedo tailcrear 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
.bashrcy 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á
tailcorrectamente. 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
findsoporte-print0como 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
-printfinterruptor de find que me permite especificar qué datos aparecen en la salida. No todas las versiones defindsoporte-printf(no es estándar) pero GNU find sí. Si se encuentra sin-printfusted, necesitará confiar-exec stat {} \;en qué momento debe renunciar a toda esperanza de portabilidad, yastatque 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 1evita que sefindenumeren los contenidos de los subdirectorios y\! -type domite 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,
sortespera que su entrada sean registros delimitados por nueva línea. Si tiene GNUsort, puede pedirle que espere registros delimitados por nulos utilizando el-zinterruptor .; para estándarsortno 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 digosortdos 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;
-znres solo una forma concisa de decir-z -n -r). Después de eso-t .(el espacio es opcional) le dicesortal carácter delimitador de campo y-k 1,2especifica los números de campo: primero y segundo (sortcuenta los campos de uno, no cero). Recuerde que un registro de muestra para el directorio actual se vería así:Esto significa que
sortse verá primero1000000000y luego0000000000al ordenar este registro. La-nopción le indicasortque 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
sortes-rpara "reversa". Por defecto, la salida de una ordenación numérica será primero los números más bajos, los-rcambia 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 GNUheadytailno 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
IFSpara que la lista de archivos no esté sujeta a división de palabras. A continuación, digoreaddos 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 variablerecordpara que cada vez que elwhileciclo se repita, tenga una sola marca de tiempo y un solo nombre de archivo. Tenga en cuenta que-des una extensión GNU; Si solo tiene un estándar,readesta técnica no funcionará y tendrá pocos recursos.Sabemos que la
recordvariable tiene tres partes, todas delimitadas por caracteres de punto. Usando lacututilidad es posible extraer una parte de ellos.Aquí se pasa todo el registro hacia
printfy desde allí canalizado acut; en bash se podía simplificar este adicionalmente utilizando una cadena de aquí acut -d. -3f- <<<"$record"un mejor rendimiento. Decimoscutdos cosas: primero con-deso, debe un delimitador específico para identificar campos (como consortel delimitador.se utiliza). El segundocutrecibe instrucciones-fpara 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 quecutleerá 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:
breaksale del bucle sin dejar que se mueva a la segunda ruta del archivo.Lo único que queda es ejecutarse
tailen 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óntailes que le proporcioné la opción--antes de expandir el nombre del archivo. Esto instruirátailque 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)headytailno 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 -1para obtener la primera línea (archivo).La salida de ese comando (el archivo más reciente) se pasa a
tailprocesar.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
-1es necesario, lolshace por ti cuando está en una tubería. Comparalsyls|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,mtimeyctime, a diferencia de Microsoft Windows,ctimeno 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
lscomando. 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í
mdenota el tiempo de modificaciónm[Mwhms][-|+]n, y lo anteriorosignifica que está ordenado de una manera (loOordena 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
lsno es lo más inteligente ...Explicación:
fuente
fuente