Yanıtlar:
Bash veya ksh'da dosya adlarını bir diziye yerleştirin ve bu dizinin tersini sırayla yineleyin.
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
Eğer ksh_arrays
seçenek ayarlanmışsa yukarıdaki kod da zsh ile çalışır (ksh emülasyon modundadır). Zsh'da daha basit bir yöntem vardır, ki bu da maçların sırasını bir glob elemesinden geriye çevirir:
for f in /var/logs/foo*.log(On); do bar $f; done
POSIX, dizileri içermez; bu nedenle, taşınabilir olmak istiyorsanız, bir dizi diziyi doğrudan saklamak için tek seçeneğiniz konumsal parametrelerdir.
set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
eval "f=\${$i}"
bar "$f"
i=$((i-1))
done
i
ve f
; Sadece bir gerçekleştirin shift
, $1
görüşmeniz için kullanın ve kendi içinde bar
test [ -z $1 ]
edin while
.
[ -z $1 ]
de [ -z "$1" ]
yararlı testlerdir (parametre ne olursa *
veya boş bir dize?). Ve her durumda burada yardımcı olmuyorlar: soru, ters sırada nasıl döngü oluşturulacağıdır.
Satır sonlarını "funky karakter" olarak düşünmüyorsanız, bunu deneyin:
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
f
durumumdaki değişkeni kırdı . Bu cevap olsa da, sıradan for
hat için bir açılan yerine hemen hemen hareket eder .
Herhangi biri, boşlukla ayrılmış bir dize listesi üzerinde yinelemenin nasıl tersine çevrileceğini anlamaya çalışıyorsa, bu işe yarar:
reverse() {
tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}
list="a bb ccc"
for i in `reverse $list`; do
echo "$i"
done
> ccc
> bb
> a
tac
GNU coreutils'in bir parçası olarak bu bir tür şok edici . Ancak çözümünüz de iyi bir çözümdür.
tac
. tac
Buradaki cevapsız cevap sayısından rağmen, belki OSX'in taclı olmadığını tahmin ediyorum. Bu durumda @ arp'ın çözümünün bir türünü kullanın - yine de anlamak daha kolaydır.
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar
İstediğiniz şekilde çalışması gerekir (bu Mac OS X'te test edildi ve aşağıda bir uyarı var).
Bulmak için man sayfasından:
-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).
Temel olarak, string + glob'unuzla eşleşen dosyaları buluyorsunuz ve her birini NUL karakteriyle sonlandırıyorsunuz. Dosya adlarınız yeni satırlar veya başka garip karakterler içeriyorsa, bu işlemi iyi yapmalı.
tail -r
borudan standart girdi alır ve onu tersine çevirir (not bu tail -r
baskılar tüm standart varsayılan olan Stdout'a girdi ve sadece son 10 satır. man tail
daha fazla bilgi için).
Daha sonra bu borulara 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).
Burada xargs, içinden geçtiğin find
ve tersine döndüğü NUL karakteriyle ayrılmış argümanları görmeyi bekler tail
.
Notum: Boş sonlandırılmış dizelerle iyi sonuçlanmadığını okudumtail
. Bu, Mac OS X'te iyi çalıştı, ancak tüm * nix'ler için geçerli olduğunu garanti edemiyorum. Dikkatlice basmak.
Ayrıca GNU Parallel'in sıklıkla xargs
alternatif olarak kullanıldığını da belirtmeliyim . Bunu da kontrol edebilirsiniz.
Bir şeyleri özlüyorum, o yüzden başkaları içeri girmeli.
tail -r
yine de desteklemiyor ... yanlış bir şey mi yapıyorum?
tac
alternatif olarak bahsetti , bu yüzden bunu denerdim
tail -r
OSX’e özgüdür ve yeni satırla sınırlandırılmış girişi ters çevirir, sıfırdan ayrılmış girişi değil. İkinci çözümünüz hiç işe yaramıyor (girişini ls
umursuyorsunuz, hangisi umursamıyor); güvenilir çalışmasını sağlayacak kolay bir düzeltme yoktur.
Örneğinizde, birkaç dosya üzerinden geçiyorsunuz, ancak bu soruyu bir dizinin üzerinden çevrilmeyi de kapsayabilecek daha genel başlığı nedeniyle veya herhangi bir sayıdaki emri temel alarak değiştirebildiğim için buldum.
İşte Zsh'da bunun nasıl yapılacağı:
Bir dizideki öğeler üzerinde dolaşıyorsanız, bu sözdizimini ( kaynak ) kullanın.
for f in ${(Oa)your_array}; do
...
done
O
bir sonraki bayrakta belirtilen emrin tersi; a
normal dizi sırasıdır.
@Gilles’in dediği gibi globbed On
dosyalarınızı tersine çevirir my/file/glob/*(On)
. Çünkü On
"ters isim sırası " dır .
Zsh sıralama bayrakları:
a
dizi sırasıL
dosya uzunluğul
bağlantı sayısım
düzenleme tarihin
isim^o
Ters sıra ( o
normal sıra)O
Ters siparişÖrnekler için bkz. Https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt ve http://reasoniamhere.com/2014/01/11/outrageously-useful-tips- -ana-daki-z-kabuk /
Mac OSX tac
komutu desteklemiyor . @Tcdyl çözümü bir for
döngüde tek bir komut çağırdığınızda çalışır . Diğer tüm durumlar için, aşmanın en basit yolu aşağıdaki gibidir.
Bu yaklaşım, dosya adlarınızda yeni satırlara sahip olmayı desteklemiyor. Bunun temel nedeni, tail -r
girişini yeni satırlarla sınırlandırılmış şekilde sıralamasıdır.
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
Ancak, newline sınırlamasını aşmanın bir yolu var. Dosya adlarınızın belirli bir karakter içermediğini biliyorsanız ('=' deyin), o zaman tr
tüm yeni satırları bu karakter haline getirmek için kullanabilir ve ardından sıralamayı yapabilirsiniz. Sonuç şöyle görünür:
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
Not: Sürümünüze bağlı olarak, karakter olarak tr
desteklemeyebilir '\0'
. Bu genellikle yerel ayarları C olarak değiştirerek işe yarar (ancak bilgisayarımda bir kez düzelttikten sonra tam olarak nasıl olduğunu tam olarak hatırlamıyorum). Bir hata mesajı alırsanız ve geçici çözümü bulamazsanız, lütfen yorum olarak gönderin, sorun gidermenize yardımcı olabilirim.
sort -r
önce borufor
, ya da üzerinden aklamals -r
.