Odpowiedzi:
W bash lub ksh umieść nazwy plików w tablicy i powtórz tę tablicę w odwrotnej kolejności.
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
Powyższy kod działa również w zsh, jeśli ksh_arrays
opcja jest ustawiona (działa w trybie emulacji ksh). W zsh istnieje prostsza metoda, polegająca na odwróceniu kolejności dopasowań za pomocą kwalifikatora glob:
for f in /var/logs/foo*.log(On); do bar $f; done
POSIX nie obejmuje tablic, więc jeśli chcesz być przenośny, jedyną opcją do bezpośredniego przechowywania tablicy ciągów są parametry pozycyjne.
set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
eval "f=\${$i}"
bar "$f"
i=$((i-1))
done
i
i f
; po prostu wykonaj shift
, użyj $1
do połączenia bar
i przetestuj [ -z $1 ]
w swoim while
.
[ -z $1 ]
nie [ -z "$1" ]
są użytecznymi testami (co jeśli parametr był *
lub pusty ciąg?). W każdym razie nie pomagają tutaj: pytanie brzmi, jak zapętlić w odwrotnej kolejności.
Spróbuj tego, chyba że rozpatrujesz łamanie linii jako „funky znaków”:
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
f
w mojej sytuacji. Ta odpowiedź działa jednak prawie jak zwykły zamiennik zwykłej for
linii.
Jeśli ktoś próbuje wymyślić sposób odwrócenia iteracji po liście ciągów rozdzielanych spacjami, działa to:
reverse() {
tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}
list="a bb ccc"
for i in `reverse $list`; do
echo "$i"
done
> ccc
> bb
> a
tac
jest częścią jądra GNU. Ale twoje rozwiązanie jest również dobre.
tac
. Chociaż na podstawie liczby tac
bez-odpowiedzi tutaj zgaduję, że może OSX nie ma tac. W takim przypadku użyj wariantu rozwiązania @ arp - i tak łatwiej to zrozumieć.
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar
Powinien działać tak, jak chcesz (zostało to przetestowane na Mac OS X i mam zastrzeżenie poniżej ...).
Ze strony podręcznika użytkownika dla find:
-print0
This primary always evaluates to true. It prints the pathname of the current file to standard output, followed by an ASCII NUL character (charac-
ter code 0).
Zasadniczo znajdujesz pliki pasujące do łańcucha + glob i kończysz każdy znakiem NUL. Jeśli twoje nazwy plików zawierają znaki nowej linii lub inne dziwne znaki, find powinien sobie z tym poradzić.
tail -r
pobiera standardowe wejście przez potok i odwraca go (zwróć uwagę, że tail -r
wypisuje wszystkie dane wejściowe na standardowe wyjście, a nie tylko na 10 ostatnich wierszy, co jest standardowym ustawieniem domyślnym. man tail
więcej informacji).
Następnie przesyłamy to do xargs -0
:
-0 Change xargs to expect NUL (``\0'') characters as separators, instead of spaces and newlines. This is expected to be used in concert with the
-print0 function in find(1).
Tutaj xargs oczekuje, że argumenty zostaną oddzielone znakiem NUL, który przekazałeś find
i odwróciłeś tail
.
Moje zastrzeżenie: przeczytałem, że tail
nie gra dobrze z ciągami zakończonymi zerem . Działa to dobrze w systemie Mac OS X, ale nie mogę zagwarantować, że tak jest w przypadku wszystkich * nix. Stąpaj ostrożnie.
Powinienem również wspomnieć, że GNU Parallel jest często używany jako xargs
alternatywa. Możesz to również sprawdzić.
Być może czegoś mi brakuje, więc inni powinni wejść.
tail -r
... czy robię coś złego?
tac
jako alternatywa, więc spróbowałbym tego zamiast tego
tail -r
jest specyficzny dla OSX i odwraca dane rozdzielane znakami nowej linii, a nie danych rozdzielanych znakiem zerowym. Twoje drugie rozwiązanie w ogóle nie działa (przesyłasz dane wejściowe ls
, co nie ma znaczenia); nie ma łatwej poprawki, która sprawiłaby, że działałby niezawodnie.
W twoim przykładzie zapętlasz kilka plików, ale znalazłem to pytanie ze względu na bardziej ogólny tytuł, który może również obejmować zapętlanie tablicy lub odwracanie w oparciu o dowolną liczbę zamówień.
Oto jak to zrobić w Zsh:
Jeśli zapętlasz elementy w tablicy, użyj tej składni ( źródło )
for f in ${(Oa)your_array}; do
...
done
O
odwraca kolejność określoną w następnej fladze; a
jest normalną kolejnością tablic.
Jak powiedział @Gilles, On
odwróci kolejność twoich globowanych plików, np my/file/glob/*(On)
. Z. To dlatego, że On
jest „odwrotną kolejnością nazw ”.
Flagi sortowania Zsh:
a
kolejność tablicL
długość plikul
liczba linkówm
Data modyfikacjin
imię^o
odwrotna kolejność ( o
normalna kolejność)O
Odwrotna kolejnośćPrzykłady można znaleźć na https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt i http://reasoniamhere.com/2014/01/11/outrageously-useful-tips- to-master-your-z-shell /
Mac OSX nie obsługuje tac
polecenia. Rozwiązanie @tcdyl działa, gdy wywołujesz pojedyncze polecenie w for
pętli. We wszystkich innych przypadkach najprostszym sposobem obejścia tego jest następujący sposób.
To podejście nie obsługuje posiadania nowych linii w nazwach plików. Podstawowym powodem jest to, że tail -r
sortuje on dane wejściowe w postaci znaku nowej linii.
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
Istnieje jednak sposób na obejście ograniczenia nowej linii. Jeśli wiesz, że twoje nazwy plików nie zawierają określonego znaku (powiedz „=”), możesz użyć, tr
aby zastąpić wszystkie znaki nowej linii, aby stać się tym znakiem, a następnie wykonać sortowanie. Wynik wyglądałby następująco:
for i in `find [directory] -name '[filename]' -print0 | tr '\n' '=' | tr '\0' '\n'
| tail -r | tr '\n' '\0' | tr '=' '\n' | xargs -0`; do [commands]; done
Uwaga: w zależności od wersji tr
może nie obsługiwać '\0'
postaci. Można to zwykle obejść, zmieniając ustawienia regionalne na C (ale nie pamiętam, jak dokładnie, ponieważ po naprawieniu raz działa teraz na moim komputerze). Jeśli pojawi się komunikat o błędzie i nie możesz znaleźć obejścia, opublikuj go jako komentarz, aby pomóc w rozwiązaniu problemu.
sort -r
przedfor
lub wypierzls -r
.