Ottieni il file più recente in una directory su Linux


183

Alla ricerca di un comando che restituirà il singolo file più recente in una directory.

Non vedere un parametro limite per ls...


1
watch -n1 'ls -Art | tail -n 1'- mostra gli ultimi file

La maggior parte delle risposte qui analizza l'output lso l'utilizzo findsenza i -print0quali è problematico per la gestione di fastidiosi nomi di file. Sempre utile menzionare: BashFAQ099 che fornisce una risposta POSIX a questo problema
kvantour

Risposte:


266
ls -Art | tail -n 1

Non molto elegante, ma funziona.


2
usando ls -Artls puoi anche visualizzare la data del file.
Josir

13
Un problema minore: questa versione reindirizza tutto l'output di lsa tail, quindi stampa solo l'ultima riga. IMHO è meglio ordinare in ordine crescente e utilizzare headinvece, come chaossuggerito. Dopo aver stampato la prima riga, la testina si chiude, quindi l'invio della riga successiva (in realtà il blocco successivo) genererà un SIGPIPE e si lschiuderà anche.
Vero

1
@TrueY Sono abbastanza d'accordo. La risposta del caos è migliore per efficienza.
dmckee --- ex gattino moderatore

2
Questa soluzione include directory e file. Questa potrebbe essere una cosa positiva o negativa; dipende da cosa vuole il singolo utente. Il motivo per cui ho sollevato questo è che la domanda originale dice "file".
Sildoreth,

2
Penso che il vantaggio previsto dall'uso della coda anziché della testa potrebbe essere quello di escludere l'inclusione della riga che descrive il totale restituito dalla ls.
Peter Scott,

155
ls -t | head -n1

Questo comando fornisce effettivamente l'ultimo file modificato nella directory di lavoro corrente.


Equivalente al mio, e forse anche più efficiente.
dmckee --- ex gattino moderatore

non funziona abbastanza per me dato che echo prima alcune informazioni nella mia ls, ma ne uso, grazie!
ack

4
@Josir Questo può essere modificato per includere il datestamp con ls -tl | head -n 1, e non deve spingere l'intera tabella attraverso la pipe come la mia.
dmckee --- ex gattino moderatore

1
@ noɥʇʎԀʎzɐɹƆls -t *.png | head -n1
caos

4
Questo restituisce una cartella se è l'ultima modifica, utilizzare: ls -Art | head -n1se si desidera specificamente l'ultimo file modificato
achasinh

79

Questa è una versione ricorsiva (ovvero trova il file aggiornato più di recente in una determinata directory o in una delle sue sottodirectory)

find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1

Modifica: usa -f 2-invece di -f 2come suggerito da Kevin


5
Ecco una soluzione per Mac:find $DIR -type f -exec stat -lt "%Y-%m-%d" {} \+ | cut -d' ' -f6- | sort -n | tail -1
utente

2
Il problema è che il comando cut tronca i percorsi con spazi invece di -f 2 usa -f2- per restituire i campi 2 alla fine della riga
Kevin

2
Come nel suggerimento del caos, se si inverte l'ordinamento utilizzando sort -nr, è possibile utilizzare head -n 1anziché tail -n 1migliorare leggermente l'efficienza. (Anche se stai ordinando una ricerca ricorsiva, ottenere la prima o l'ultima riga non sarà la parte lenta.)
destenson

2
Molto utile! Lo trovo più amichevole se convogliato a lui però:find ./ -type f -printf "%T@ %p\n" -ls | sort -n | cut -d' ' -f 2- | tail -n 1 | xargs -r ls -lah
Simon,

La versione Mac dell'utente @ ordina / visualizza solo la data, non l'ora. Ecco una versione fissa:find $DIR -type f -exec stat -lt "%F %T" {} \+ | cut -d' ' -f6- | sort -n | tail -1
yoz

12

Una nota sull'affidabilità:

Poiché il carattere di nuova riga è valido come qualsiasi in un nome di file, qualsiasi soluzione che si basa su linee come head/tail quelle basate su è difettosa.

Con GNU ls, un'altra opzione è usare l' --quoting-style=shell-alwaysopzione e un basharray:

eval "files=($(ls -t --quoting-style=shell-always))"
((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

(aggiungi l' -Aopzione als se vuoi considerare anche i file nascosti).

Se si desidera limitare a file regolari (ignorare directory, fifo, dispositivi, collegamenti simbolici, socket ...), è necessario ricorrere a GNU find .

Con bash 4.4 o successivo (per readarray -d versioni ) e GNU coreutils 8.25 o versioni successive (per cut -z):

readarray -t -d '' files < <(
  LC_ALL=C find . -maxdepth 1 -type f ! -name '.*' -printf '%T@/%f\0' |
  sort -rzn | cut -zd/ -f2)

((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

O ricorsivamente:

readarray -t -d '' files < <(
  LC_ALL=C find . -name . -o -name '.*' -prune -o -type f -printf '%T@%p\0' |
  sort -rzn | cut -zd/ -f2-)

Il migliore qui sarebbe usare zsh e le sue qualificazioni glob invece di bashevitare tutto questo fastidio:

File regolare più recente nella directory corrente:

printf '%s\n' *(.om[1])

Di cui quelli nascosti:

printf '%s\n' *(D.om[1])

Secondo più recente:

printf '%s\n' *(.om[2])

Controlla l'età dei file dopo la risoluzione del collegamento simbolico:

printf '%s\n' *(-.om[1])

ricorsivamente:

printf '%s\n' **/*(.om[1])

Inoltre, con il sistema di completamento (compinit e co) abilitato,Ctrl+Xm diventa un completatore che si espande nel file più recente.

Così:

VI Ctrl+Xm

Ti farebbe modificare il file più recente (avrai anche la possibilità di vedere quale prima di premere Return ).

VI Alt+2Ctrl+Xm

Per il secondo file più recente.

vi * .cCtrl+Xm

per il più recente c file .

vi * (.)Ctrl+Xm

per il file regolare più recente (non directory, né fifo / dispositivo ...) e così via.


Grazie per i zshsuggerimenti. Potresti fornire un link per maggiori dettagli a riguardo nei documenti zsh?
Congelato il

@freezed, vediinfo zsh qualifiers
Stephane Chazelas il

Grazie @Stephane Chazelas
congelato il

9

Io uso:

ls -ABrt1 --group-directories-first | tail -n1

Mi dà solo il nome del file, escluse le cartelle.


a meno che una directory non
contenga

8

ls -lAtr | tail -1

Le altre soluzioni non includono i file che iniziano con '.' .

Questo comando includerà anche '.'e '..', che può essere o meno quello che vuoi:

ls -latr | tail -1


Tornerà questo "." se la directory è stata modificata più recentemente di qualsiasi file contenuto (diciamo con una cancellazione)? Forse quello è il comportamento desiderato, forse no. Ma hai ragione in entrambi i modi.
dmckee --- ex gattino moderatore

6

Variante in corto basata sulla risposta di dmckee:

ls -t | head -1

ma la -1sintassi head è stata deprecata da tempo e -n 1dovrebbe essere usata.
tink

5

Mi piace echo *(om[1])( zshsintassi) in quanto dà solo il nome del file e non invoca nessun altro comando.


1
Funziona bene se stai usando zsh. Non stai usando zsh? Penso che bash sia l'impostazione predefinita in Ubuntu; puoi installare zsh o puoi trovare un comando equivalente per bash.
MikeB,

3
Il comando è "echo"; valuta solo i suoi parametri e li invia all'output standard. In questo caso, il qualificatore glob "om [1]" ha "o", il che significa ordinare i file corrispondenti per "m", che è tempo modificato. E da quell'elenco ordinato, prendi [1], che è il primo file. Puoi leggere le informazioni sui qualificatori di glob: zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers
MikeB

4

La soluzione find / sort funziona alla grande fino a quando il numero di file diventa davvero grande (come un intero file system). Usa invece awk per tenere traccia del file più recente:

find $DIR -type f -printf "%T@ %p\n" | 
awk '
BEGIN { recent = 0; file = "" }
{
if ($1 > recent)
   {
   recent = $1;
   file = $0;
   }
}
END { print file; }' |
sed 's/^[0-9]*\.[0-9]* //'

3

Personalmente preferisco usare il minor numero possibile di bashcomandi non incorporati (per ridurre il numero di costose fork e exec syscalls). Per ordinare per data il lsnecessario per essere chiamato. Ma l'uso di headnon è davvero necessario. Uso il seguente one-liner (funziona solo su sistemi che supportano le pipe dei nomi):

read newest < <(ls -t *.log)

o per ottenere il nome del file più vecchio

read oldest < <(ls -rt *.log)

(Fai attenzione allo spazio tra i due segni '<'!)

Se sono necessari anche i file nascosti, potrebbe essere aggiunto un arg.

Spero che questo possa aiutare.


Dovresti spiegare che il nome del file è archiviato in $ old / newest var. Ma +1 per il minor numero di forchette.
squareatom

@squareatom Pensavo che leggere fosse abbastanza ben noto integrato. Ma hai ragione, forse no. Grazie per il tuo commento!
TrueY,

3
Supponendo che tu sappia che cos'è un built-in, sei probabilmente corretto. Ma stavo solo pensando alla domanda del PO. Hanno chiesto un comando che avrebbe restituito qualcosa. Tecnicamente la tua soluzione non produce nulla. Quindi aggiungi "&& echo $ newest" o simile alla fine ;-)
squareatom

3

usando l'opzione ricorsiva R .. puoi considerare questo come un miglioramento per buone risposte qui

ls -arRtlh | tail -50

2
ls -t -1 | sed '1q'

Mostrerà l'ultimo elemento modificato nella cartella. Associa grepper trovare le ultime voci con le parole chiave

ls -t -1 | grep foo | sed '1q'

che cos'è il '1q'? 1è per la prima riga equivalente a head -n 1ciò che è q?
HattrickNZ,

2

ricorsivamente:

find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

1

prova questo semplice comando

ls -ltq  <path>  | head -n 1

Se si desidera il nome del file - ultima modifica, percorso = /ab/cd/*.log

Se si desidera il nome della directory - ultima modifica, percorso = / ab / cd / * /


1

Presumendo che non ti interessi dei file nascosti che iniziano con a .

ls -rt | tail -n 1

Altrimenti

ls -Art | tail -n 1

1

Con solo i builtin di Bash, seguendo da vicino BashFAQ / 003 :

shopt -s nullglob

for f in * .*; do
    [[ -d $f ]] && continue
    [[ $f -nt $latest ]] && latest=$f
done

printf '%s\n' "$latest"

0

Tutte quelle soluzioni ls / tail funzionano perfettamente per i file in a directory, ignorando le sottodirectory.

Per includere tutti i file nella ricerca (ricorsivamente), è possibile utilizzare find. gioele ha suggerito di ordinare l'output find formattato. Ma fai attenzione agli spazi bianchi (il suo suggerimento non funziona con gli spazi bianchi).

Questo dovrebbe funzionare con tutti i nomi di file:

find $DIR -type f -printf "%T@ %p\n" | sort -n | sed -r 's/^[0-9.]+\s+//' | tail -n 1 | xargs -I{} ls -l "{}"

Ordina per mtime, vedi man find:

%Ak    File's  last  access  time in the format specified by k, which is either `@' or a directive for the C `strftime' function.  The possible values for k are listed below; some of them might not be available on all systems, due to differences in `strftime' between systems.
       @      seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
%Ck    File's last status change time in the format specified by k, which is the same as for %A.
%Tk    File's last modification time in the format specified by k, which is the same as for %A.

Quindi basta sostituire %T con %Cper ordinare per ctime.


Hai ragione riguardo al problema degli spazi bianchi con il suggerimento di @gioele, ma devi solo aggiungere un trattino all'opzione -f per renderlo un intervallo per risolvere questo: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1 O in alternativa, mantieni tutto tranne il primo campo: find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 1 --complement | tail -n 1
Aaron

0

Trovare il file più aggiornato in ogni directory secondo uno schema, ad esempio le sottodirectory della directory di lavoro che hanno un nome che termina con "tmp" (senza distinzione tra maiuscole e minuscole):

find . -iname \*tmp -type d -exec sh -c "ls -lArt {} | tail -n 1" \;

0
ls -Frt | grep "[^/]$" | tail -n 1

1
Esistono altre risposte che forniscono la domanda del PO e sono state pubblicate molti anni fa. Quando pubblichi una risposta, assicurati di aggiungere una nuova soluzione o una spiegazione sostanzialmente migliore, soprattutto quando rispondi a domande più vecchie.
help-info.de

2
@ help-info.de Non votare per eliminare le risposte solo a codice. Potrebbero non essere grandi, ma la cancellazione è per cose che non sono risposte
Machavity

@Machavity - Spero di non aver fallito e ho fatto un commento solo per una risposta tardiva.
help-info.de

0

Se vuoi ottenere il file modificato più recente includendo anche tutte le sottodirectory puoi farlo con questo piccolo oneliner:

find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

Se si desidera fare lo stesso non per i file modificati, ma per i file a cui si accede è necessario modificare semplicemente

% Y parametro dal stat comando per % X . E il tuo comando per i file di accesso più recenti è simile al seguente:

find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

Per entrambi i comandi è inoltre possibile modificare il parametro var = "1" se si desidera elencare più di un solo file.


-1

Anch'io dovevo farlo, e ho trovato questi comandi. questi funzionano per me:

Se si desidera l'ultimo file entro la data di creazione nella cartella (ora di accesso):

ls -Aru | tail -n 1  

E se vuoi l'ultimo file che ha dei cambiamenti nel suo contenuto (modifica ora):

ls -Art | tail -n 1  
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.