2012-02-14 12 views

Odpowiedz

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

$(...) ocenia oświadczenie w podpowłoce i zwraca wynik.

+7

Mimo akceptacji i znacznej przewartościowania istnieje kilka problemów z tym rozwiązaniem. Nie działa, jeśli najnowszy element w katalogu nie jest katalogiem. Nie działa, jeśli najnowszy podkatalog ma nazwę zaczynającą się od ".". Nie działa, jeśli najnowszy podkatalog ma nazwę zawierającą znak nowej linii. [Shellcheck] (http://www.shellcheck.net/) narzeka na użycie 'ls'. Zobacz [ParsingLs - Greg's Wiki] (http://mywiki.wooledge.org/ParsingLs), aby uzyskać szczegółowe wyjaśnienie niebezpieczeństw związanych z przetwarzaniem danych wyjściowych 'ls'. – pjh

4

Powyższe rozwiązanie nie uwzględnia takich rzeczy, jak zapisywane i usuwane pliki z katalogu, w wyniku czego zwracany jest katalog górny zamiast najnowszego podkatalogu.

Inną kwestią jest to, że to rozwiązanie zakłada, że ​​katalog zawiera tylko inne katalogi, a nie zapisywane pliki.

Powiedzmy utworzyć plik o nazwie „test.txt”, a następnie ponownie uruchom polecenie:

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

Rezultatem jest test.txt wyświetlane zamiast ostatniego zmodyfikowanego katalogu.

Proponowane rozwiązanie "działa", ale tylko w najlepszym przypadku.

zakładając, że masz maksymalnie 1 głębokości katalogów, lepszym rozwiązaniem jest użycie:

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

Wystarczy zamienić „/ backups /” część dla aktualnej ścieżki.

Jeśli chcesz uniknąć wyświetlania bezwzględną ścieżkę w skrypcie bash, zawsze można użyć czegoś takiego:

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

Pomimo przegranych, to rozwiązanie nie działa. 'find/backups/* -type d -prune -exec ...' przetwarza katalogi w kolejności, w jakiej są tworzone, gdy powłoka rozszerzy '/ backups/*'. Kolejność określają nazwy, a nie znaczniki czasu. Ostatni z wymienionych katalogów będzie normalnie _nie_ być najnowszym. – pjh

0

Aby uzyskać najnowszy folder używając ls -t może trzeba odróżnić pliki z folderów, jeśli katalog nie ma tylko katalogów. Stosując prostą pętlę trzeba będzie bezpieczny i szybki rezultat, a także pozwala na łatwe wdrożenie różnych filtrów w przyszłości:

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

opracowano blok:

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 

Strzeż logiki continue na moim opracowanego bloku :

else 
    continue # Look for the next newest item 

Nie użyjesz go. Umieściłem to tylko ze względu na twoją widoczność, ponieważ w tym przypadku nie wpłynęłoby to na wyniki.

0

Cóż, myślę, że jest to rozwiązanie najbardziej efektywne:

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

Wyjaśnienie, dlaczego to jest trochę lepiej:

Nie potrzebujemy sub-muszle (oprócz jednego uzyskania wyniku do zmiennej bash). Nie potrzebujemy niepotrzebnego -exec ls -d na końcu polecenia find, już wypisuje listing katalogu. Możemy łatwo to zmienić, np. aby wykluczyć pewne wzorce. Na przykład, jeśli chcesz sekund najnowszego katalogu, ponieważ pliki kopii zapasowych są najpierw zapisywane w tmp dir w tej samej ścieżce:

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

Dla mnie to nie zamawianie folderów. – pfnuesel

0

Ten ia czystego roztworu bash

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" 

pomija dowiązania , w tym dowiązania symboliczne do katalogów, które mogą być lub nie są właściwe. Pomija inne nie-katalogi. Obsługuje katalogi, których nazwy zawierają dowolne znaki, w tym znaki nowej linii i kropki wiodące.

13

Istnieje proste rozwiązanie tego używając tylko ls:

BACKUPDIR=$(ls -td /backups/*/ | head -1) 
  • -t zamówień według czasu (najpierw najnowsze)
  • -d wymienia tylko elementy z tego folderu
  • */ tylko wymienia katalogi
  • head -1 zwraca pierwszy element

Nie wiedziałem o */, dopóki nie znalazłem Listing only directories using ls in bash: An examination.

+1

W odpowiedzi na komentarz pjh dotyczący zaakceptowanej odpowiedzi "Nie działa, jeśli najnowszy katalog zaczyna się od". "", Co również odnosi się do mojej odpowiedzi. Jeśli chcesz uwzględnić foldery zaczynające się od. (ale wykluczyć ./ i ../) można zmienić ls na: ls -td /backups/{.[^.],}?*/ – Martin