For döngüsünü nasıl tersine çeviririm?


26

Döngüyü ters sırada nasıl düzgün yaparım for?

for f in /var/logs/foo*.log; do
    bar "$f"
done

Dosya adlarındaki korkak karakterleri bozmayan bir çözüme ihtiyacım var.


5
Sadece sort -rönce boru for, ya da üzerinden aklama ls -r.
David Schwartz

Yanıtlar:


27

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_arraysseç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

Eğer konum parametreleri kullanmaya başladıktan sonra, sizin değişkenler için gerek yoktur ive f; Sadece bir gerçekleştirin shift, $1görüşmeniz için kullanın ve kendi içinde bartest [ -z $1 ]edin while.
kullanici1404316

@ user1404316 Bu, elemanları artan düzende yinelemenin aşırı karmaşık bir yoludur . Ayrıca, yanlış: ne [ -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.
Gilles 'SO- kötülük yapmayı bırak'

Soru özellikle / var / log içindeki dosya isimleri üzerinde yinelendiğini söylüyor, bu nedenle parametrelerin hiçbirinin "*" veya boş olmayacağını varsaymak güvenlidir. Yine de, ters sıra noktasında düzeltilmiş duruyorum.
user1404316,

7

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

Satır sonları ile çalışan bir yöntem var mı? (Nadir olduğunu biliyorum, ama en azından öğrenme uğruna, doğru kod yazmanın mümkün olup olmadığını bilmek isterdim.)
Mehrdad

Akışı tersine çevirmek için tac kullanmak için Creative, satır sonları gibi istenmeyen karakterlerden kurtulmak istiyorsanız tr -d '\ n' konumuna yönlendirebilirsiniz.
Johan

4
Bu, dosya adları yeni satırlar, ters eğik çizgiler veya yazdırılamayan karakterler içeriyorsa kırılır. Bkz mywiki.wooledge.org/ParsingLs ve nasıl bir dosyanın hatları üzerinden döngü? (ve bağlantılı iplikler).
Gilles 'SO- kötülük' dur '22

En çok oy alan cevap fdurumumdaki değişkeni kırdı . Bu cevap olsa da, sıradan forhat için bir açılan yerine hemen hemen hareket eder .
Serge Stroobandt

2

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

2
Sistemimde taciz yok; Sağlam mı bilmiyorum ama x için $ {mylist}; do revv = "$ {x} $ {revv}"; yapılır
arp

@arp tacGNU coreutils'in bir parçası olarak bu bir tür şok edici . Ancak çözümünüz de iyi bir çözümdür.
ACK_stoverflow

@ACK_stoverflow Orada Linux userland araçları olmadan sistemler var.
Kusalananda

@Kusalananda Yalnızca Linux'un GNU coreutils kullandığını mı söylüyorsunuz? LOL. Meşgul kutu bile var tac. tacBuradaki 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.
ACK_stoverflow

@ACK_stoverflow Demek istediğim, evet.
Kusalananda

1
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 -rbaskılar tüm standart varsayılan olan Stdout'a girdi ve sadece son 10 satır. man taildaha 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 findve 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 xargsalternatif olarak kullanıldığını da belirtmeliyim . Bunu da kontrol edebilirsiniz.

Bir şeyleri özlüyorum, o yüzden başkaları içeri girmeli.


2
+1 harika cevap. Görünüşe göre Ubuntu tail -ryine de desteklemiyor ... yanlış bir şey mi yapıyorum?
Mehrdad

1
Hayır, olduğunu sanmıyorum. Linux makinem yok ama 'linux tail man' için hızlı bir google bunu bir seçenek olarak göstermiyor. sunaku tacalternatif olarak bahsetti , bu yüzden bunu denerdim
tcdyl

Ben de cevabı başka bir alternatif içerecek şekilde düzenledim
tcdyl

Boğmaca +1 :( Dediğimde +1'i unuttum! Yaptım! Üzgünüm haha ​​:)
Mehrdad

4
tail -rOSX’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 lsumursuyorsunuz, hangisi umursamıyor); güvenilir çalışmasını sağlayacak kolay bir düzeltme yoktur.
Gilles 'SO- kötülük' dur '22

1

Ö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

Obir sonraki bayrakta belirtilen emrin tersi; anormal dizi sırasıdır.

@Gilles’in dediği gibi globbed Ondosyaları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ğu
  • l bağlantı sayısı
  • m düzenleme tarihi
  • n isim
  • ^oTers sıra ( onormal 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 /


0

Mac OSX tackomutu desteklemiyor . @Tcdyl çözümü bir fordö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 -rgiriş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 trtü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 trdesteklemeyebilir '\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.


0

ls -r@David Schwartz tarafından belirtildiği gibi kolay bir yol kullanıyor

for f in $(ls -r /var/logs/foo*.log); do
    bar "$f"
done

-4

Bunu dene:

for f in /var/logs/foo*.log; do
bar "$f"
done

Bence en basit yol bu.


3
Soru “ forters sırada döngü ” istedi .
Manatwork
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.