Câu trả lời:
Trong bash hoặc ksh, đặt tên tệp trong một mảng và lặp lại trên mảng đó theo thứ tự ngược lại.
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
Mã ở trên cũng hoạt động trong zsh nếu ksh_arrays
tùy chọn được đặt (nó ở chế độ mô phỏng ksh). Có một phương pháp đơn giản hơn trong zsh, đó là đảo ngược thứ tự của các trận đấu thông qua vòng loại toàn cầu:
for f in /var/logs/foo*.log(On); do bar $f; done
POSIX không bao gồm các mảng, vì vậy nếu bạn muốn di động, tùy chọn duy nhất của bạn để lưu trữ trực tiếp một chuỗi các chuỗi là các tham số vị trí.
set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
eval "f=\${$i}"
bar "$f"
i=$((i-1))
done
i
và f
; chỉ cần thực hiện một shift
, sử dụng $1
cho cuộc gọi của bạn bar
và kiểm tra [ -z $1 ]
trong của bạn while
.
[ -z $1 ]
cũng không phải [ -z "$1" ]
là các thử nghiệm hữu ích (nếu tham số là *
hoặc chuỗi rỗng thì sao?). Và trong mọi trường hợp họ không giúp đỡ ở đây: câu hỏi là làm thế nào để lặp theo thứ tự ngược lại.
Hãy thử điều này, trừ khi bạn coi ngắt dòng là "ký tự sôi nổi":
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
f
trong tình huống của tôi. Câu trả lời này, hoạt động khá nhiều như là một thay thế thả xuống cho for
dòng thông thường .
Nếu bất cứ ai đang cố gắng tìm ra cách đảo ngược lặp lại trong danh sách chuỗi được phân tách bằng dấu cách, thì điều này hoạt động:
reverse() {
tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}
list="a bb ccc"
for i in `reverse $list`; do
echo "$i"
done
> ccc
> bb
> a
tac
là một phần của lõi GNU. Nhưng giải pháp của bạn cũng là một trong những tốt.
tac
. Mặc dù từ số lượng tac
phản hồi không có ở đây, tôi đoán rằng có lẽ OSX không có tac. Trong trường hợp đó, hãy sử dụng một số biến thể của giải pháp @ arp - dù sao cũng dễ hiểu hơn.
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar
Nên vận hành theo cách bạn muốn (điều này đã được thử nghiệm trên Mac OS X và tôi có một cảnh báo bên dưới ...).
Từ trang người đàn ông để tìm:
-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).
Về cơ bản, bạn đang tìm các tệp khớp với chuỗi + toàn cầu của mình và kết thúc mỗi tệp có ký tự NUL. Nếu tên tệp của bạn chứa dòng mới hoặc các ký tự lạ khác, hãy tìm cách xử lý tốt việc này.
tail -r
đưa đầu vào tiêu chuẩn qua đường ống và đảo ngược nó (lưu ý rằng tail -r
in tất cả đầu vào thành thiết bị xuất chuẩn, và không chỉ 10 dòng cuối cùng, là mặc định tiêu chuẩn. man tail
để biết thêm).
Chúng tôi sau đó dẫn đường đó đến 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).
Ở đây, xargs hy vọng sẽ thấy các đối số được phân tách bằng ký tự NUL mà bạn truyền từ find
và đảo ngược với tail
.
Lời cảnh báo của tôi: Tôi đã đọc rằng tail
nó không chơi tốt với các chuỗi kết thúc null . Điều này hoạt động tốt trên Mac OS X, nhưng tôi không thể đảm bảo đó là trường hợp cho tất cả * nixes. Bước đi cẩn thận.
Tôi cũng nên đề cập rằng GNU Parallel thường được sử dụng xargs
thay thế. Bạn cũng có thể kiểm tra xem.
Tôi có thể đang thiếu một cái gì đó, vì vậy những người khác nên kêu vang.
tail -r
mặc dù ... tôi có làm gì sai không?
tac
như một giải pháp thay thế, vì vậy tôi sẽ thử điều đó, thay vào đó
tail -r
dành riêng cho OSX và đảo ngược đầu vào được phân tách bằng dòng mới, không phải đầu vào được phân tách bằng null. Giải pháp thứ hai của bạn hoàn toàn không hoạt động (bạn đang đầu vào ls
, không quan tâm); không có sửa chữa dễ dàng mà sẽ làm cho nó hoạt động đáng tin cậy.
Trong ví dụ của bạn, bạn đang lặp qua một số tệp, nhưng tôi đã tìm thấy câu hỏi này vì tiêu đề chung hơn của nó cũng có thể bao gồm việc lặp qua một mảng hoặc đảo ngược dựa trên bất kỳ số lượng đơn đặt hàng nào.
Đây là cách để làm điều đó trong Zsh:
Nếu bạn đang lặp qua các phần tử trong một mảng, hãy sử dụng cú pháp ( nguồn ) này
for f in ${(Oa)your_array}; do
...
done
O
đảo ngược thứ tự được chỉ định trong cờ tiếp theo; a
là thứ tự mảng bình thường.
Như @Gilles đã nói, On
sẽ đảo ngược thứ tự các tập tin toàn cầu của bạn, ví dụ như với my/file/glob/*(On)
. Đó là bởi vì On
" thứ tự tên ngược ."
Cờ sắp xếp Zsh:
a
thứ tự mảngL
chiều dài tập tinl
số lượng liên kếtm
Ngày sửa đổin
Tên^o
thứ tự ngược lại ( o
là thứ tự bình thường)O
trật tự ngượcVí dụ: xem https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt và http://reasoniamhere.com/2014/01/11/outrageiously-usiously-tips- to-master-your-z-shell /
Mac OSX không hỗ trợ tac
lệnh. Giải pháp của @tcdyl hoạt động khi bạn đang gọi một lệnh đơn trong một for
vòng lặp. Đối với tất cả các trường hợp khác, sau đây là cách đơn giản nhất để khắc phục nó.
Cách tiếp cận này không hỗ trợ việc có dòng mới trong tên tệp của bạn. Lý do cơ bản là, tail -r
sắp xếp đầu vào của nó như được phân định bởi các dòng mới.
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
Tuy nhiên, có một cách để vượt qua giới hạn dòng mới. Nếu bạn biết tên tệp của mình không chứa một ký tự nào đó (giả sử '='), thì bạn có thể sử dụng tr
để thay thế tất cả các dòng mới để trở thành ký tự này, sau đó thực hiện sắp xếp. Kết quả sẽ như sau:
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
Lưu ý: tùy thuộc vào phiên bản của bạn tr
, nó có thể không hỗ trợ '\0'
dưới dạng ký tự. Điều này thường có thể được giải quyết bằng cách thay đổi ngôn ngữ thành C (nhưng tôi không nhớ chính xác như thế nào, vì sau khi sửa nó một lần thì nó hoạt động trên máy tính của tôi). Nếu bạn nhận được thông báo lỗi và bạn không thể tìm thấy cách giải quyết, thì vui lòng gửi nó dưới dạng nhận xét, để tôi có thể giúp bạn khắc phục sự cố.
sort -r
trướcfor
, hoặc giặt quals -r
.