tutorial Ottieni la nuova directory in bash su una variabile




bin bash (5)

Mi piacerebbe trovare la sottodirectory più recente in una directory e salvare il risultato in variabile in bash.

Qualcosa come questo:

ls -t /backups | head -1 > $BACKUPDIR

Qualcuno può aiutare?


Bene, penso che questa soluzione sia la più efficiente:

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

Spiegazione perché questo è un po 'meglio:

Non abbiamo bisogno di sub-shell (a parte quello per ottenere il risultato nella variabile bash). Non abbiamo bisogno di un inutile -exec ls -d alla fine del comando find , stampa già l'elenco delle directory. Possiamo facilmente modificarlo, ad esempio per escludere determinati modelli. Ad esempio, se si desidera la seconda directory più recente, poiché i file di backup vengono prima scritti in una directory tmp nello stesso percorso:

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

C'è una soluzione semplice a questo usando solo ls :

BACKUPDIR=$(ls -td /backups/*/ | head -1)
  • -t ordini in base al tempo (prima l'ultimo)
  • -d elenca solo gli elementi da questa cartella
  • */ elenca soltanto le directory
  • head -1 restituisce il primo oggetto

Non sapevo di */ fino a quando ho trovato solo le directory che usavano ls in bash: un esame .


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

$(...) valuta l'istruzione in una subshell e restituisce l'output.


Per ottenere la cartella più recente usando ls -t potresti dover differenziare i file dalle cartelle se la tua directory non ha solo le directory. Usando un ciclo semplice avrai un risultato sicuro e veloce e potrai anche implementare facilmente diversi filtri in futuro:

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

Blocco elaborato:

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

Attenti alla continue logica sul mio blocco elaborato:

else
  continue # Look for the next newest item

Non lo userai. L'ho messo lì solo per la tua visibilità, perché in questo caso non influirebbe sui risultati.


La soluzione di cui sopra non tiene conto di cose come i file che vengono scritti e rimossi dalla directory, con il risultato che la directory superiore viene restituita al posto della sottodirectory più recente.

L'altro problema è che questa soluzione presuppone che la directory contenga solo altre directory e non i file scritti.

Diciamo che creo un file chiamato "test.txt" e poi eseguo nuovamente questo comando:

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

Il risultato è test.txt che appare invece dell'ultima directory modificata.

La soluzione proposta "funziona" ma solo nel migliore dei casi.

Supponendo che tu abbia un massimo di 1 profondità di directory, una soluzione migliore è usare:

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

Basta scambiare la parte "/ backups" per il tuo percorso attuale.

Se vuoi evitare di mostrare un percorso assoluto in uno script bash, puoi sempre usare qualcosa del genere:

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




bash