2012-02-14 8 views

Respuesta

25
BACKUPDIR=$(ls -t /backups | head -1) 

$(...) evalúa la declaración en un subnivel y devuelve la salida.

+7

A pesar de ser aceptado y muy votado, hay varios problemas con esta solución. No funciona si el elemento más nuevo en el directorio no es un directorio. No funciona si el subdirectorio más nuevo tiene un nombre que comienza con '.'. No funciona si el subdirectorio más nuevo tiene un nombre que contiene una nueva línea. [Shellcheck] (http://www.shellcheck.net/) se queja del uso de 'ls'. Ver [ParsingLs - Wiki de Greg] (http://mywiki.wooledge.org/ParsingLs) para una explicación detallada de los peligros de procesar la salida de 'ls'. – pjh

4

La solución anterior no tiene en cuenta cosas como archivos que se escriben y eliminan del directorio, lo que hace que se devuelva el directorio superior en lugar del subdirectorio más nuevo.

El otro problema es que esta solución asume que el directorio solo contiene otros directorios y no archivos que se escriben.

Digamos que puedo crear un archivo llamado "test.txt" y vuelva a ejecutar de nuevo este comando:

echo "test" > test.txt 
ls -t /backups | head -1 
test.txt 

El resultado es test.txt aparecer en lugar del último directorio modificado.

La solución propuesta "funciona" pero solo en el mejor de los casos.

Asumiendo que tienen una profundidad máxima de 1 directorio, una mejor solución es utilizar:

find /backups/* -type d -prune -exec ls -d {} \; |tail -1 

sólo cambio el "//backups" parte de su trayectoria real.

Si desea evitar mostrar una ruta absoluta en una escritura del golpe, siempre se puede usar algo como esto:

LOCALPATH=/backups 
DIRECTORY=$(cd $LOCALPATH; find * -type d -prune -exec ls -d {} \; |tail -1) 
+1

A pesar de los votos a favor, esta solución no funciona. 'find/backups/* -type d -prune -exec ...' procesa directorios en el orden en que se producen cuando el shell expande '/ backups/*'. El orden está determinado por los nombres, no por las marcas de tiempo. El último directorio enumerado normalmente _no_ será el más nuevo. – pjh

0

Para obtener la carpeta más reciente es el uso de ls -t puede que tenga que separar los archivos de las carpetas si su el directorio no tiene solo directorios. El uso de un simple lazo que tendrá un resultado seguro y rápido y que también permite implementar fácilmente diferentes filtros en el futuro:

while read i ; do if [ -d "${i}" ] ; then newestFolder="${i}" ; break ; fi ; done < <(ls -t) 

Elaborado bloque:

while read currentItemOnLoop # While reading each line of the file 
do 
    if [ -d "${currentItemOnLoop}" ] # If the item is a folder 
    then 
    newestFolder="${currentItemOnLoop}" # Then save it into the "newestFolder" variable 
    break # and stop the loop 
    else 
    continue # Look for the next newest item 
    fi 
done < <(ls -t) # Sending the result of "ls -t" as a "file" to the "while read" loop 

Cuidado con la lógica continue en mi bloque elaborada :

else 
    continue # Look for the next newest item 

No lo usará. Lo puse allí solo por su visibilidad ya que en este caso no afectaría los resultados.

0

Bueno, creo que esta solución es la más eficiente:

path="/my/dir/structure/*" 
backupdir=$(find $path -type d -prune | tail -n 1) 

explicación de por qué esto es un poco mejor:

No necesitamos sub-cáscaras (aparte de la otra para conseguir el resultado en la variable bash). No necesitamos un inútil -exec ls -d al final del comando find, ya imprime la lista del directorio. Podemos alterar esto fácilmente, p. para excluir ciertos patrones. Por ejemplo, si desea que el directorio de segundo más reciente, ya que los archivos de copia de seguridad se escriben primero en un dir tmp en el mismo camino:

backupdir=$(find $path -type -d -prune -not -name "*temp_dir" | tail -n 1) 
+0

Para mí, esto no está ordenando las carpetas. – pfnuesel

0

Este ia una solución Bash pura:

topdir=/backups 
BACKUPDIR= 

# Handle subdirectories beginning with '.', and empty $topdir 
shopt -s dotglob nullglob 

for file in "$topdir"/* ; do 
    [[ -L $file || ! -d $file ]] && continue 
    [[ -z $BACKUPDIR || $file -nt $BACKUPDIR ]] && BACKUPDIR=$file 
done 

printf 'BACKUPDIR=%q\n' "$BACKUPDIR" 

, evitando pasar por enlaces simbólicos , incluyendo enlaces simbólicos a directorios, lo que puede o no ser lo correcto. Se salta otros no directorios. Maneja directorios cuyos nombres contienen cualquier carácter, incluidas líneas nuevas y puntos iniciales.

13

Hay una solución simple a este utilizando sólo ls:

BACKUPDIR=$(ls -td /backups/*/ | head -1) 
  • -t pedidos por el tiempo (por fecha)
  • -d sólo las listas de artículos de esta carpeta
  • */ sólo las listas de directorios
  • head -1 devuelve el primer artículo

No sabía acerca de */ hasta que encontré Listing only directories using ls in bash: An examination.

+1

En respuesta al comentario de pjh sobre la respuesta aceptada "No funciona si el directorio más nuevo comienza con '.'", Que también se relaciona con mi respuesta. Si desea incluir carpetas que comiencen por. (pero excluya ./ y ../) puede cambiar el ls a: ls -td /backups/{.[^.],}?*/ – Martin

Cuestiones relacionadas