2016-05-14 38 views
5

Tüm git depolarını almak için bir bash işlevi yazıyorum, ancak tüm git deposu yol adlarını patharray dizisine depolamak istediğimde bir sorunla karşılaştım. İşte kod:Bir pipeline komutundan dizi değişkeni ekleme

gitrepo() { 
    local opt 

    declare -a patharray 
    locate -b '\.git' | \ 
     while read pathname 
     do 
      pathname="$(dirname ${pathname})" 
      if [[ "${pathname}" != *.* ]]; then 
      # Note: how to add an element to an existing Bash Array 
       patharray=("${patharray[@]}" '\n' "${pathname}") 
       # echo -e ${patharray[@]} 
      fi 
     done 
    echo -e ${patharray[@]} 
} 

Ben patharray diziye bütün depo yolları kaydetmek istiyorum ama locate ve while komuta oluşur pipeline dışına alamıyor.
pipeline komutunda diziyi bulabilirim, yorumsuz komut # echo -e ${patharray[@]} iş göremezse iyi çalışır, bu yüzden sorunu nasıl çözebilirim?

Ve export komutunu denedim, ancak patharray hattını geçemeyeceği anlaşılıyor.

+0

'yankı -e' da (onlar ... orada olmak çok büyük olasılıkla değil) yollarında tersbölüleri genişleyecektir. –

+0

Hatırlattığınız için teşekkürler, 'printf' kullanmak daha iyi bir yoldur. – zhenguoli

cevap

2

Önce, bir dizi değişkene ekleme dahaile yapılır: man bash | less +/Process\ Substitution) - Ayrıca detaylar için Bash kılavuzuna bakın Tüm diziyi dönüştürmek istemediğiniz sürece 0 veya array+=("value1" "value2" "etc").

Şimdi, pipeline commands are run in subprocesses'dan beri, bir boru hattı komutunun içindeki bir değişkene yapılan değişiklikler dışarısına yayılmayacaktır.Bunu aşmanın birkaç seçenek (çoğu Greg's BashFAQ/024 listelenmiştir) vardır:

  • Stdout'a içinden geçmesi sonucunu yerine

    • en basit; yollarında herhangi bir özel karakterler ayırıcı olarak \0 kullanarak güvenilir ele alınabilir
    • (there are ways to return a proper variable rağmen) Eğer (\0 -separated okuma listeleri için Capturing output of find . -print0 into a bash array bakınız) işlevinden değeri elde etmek sonuçta O yapmanız gerekir

      locate -b0 '\.git' | while read -r -d '' pathname; do dirname -z "$pathname"; done 
      

      veya basitçe

      locate -b0 '\.git' | xargs -0 dirname -z 
      
  • av oid

    • önlemek boru hattı tüm

      • geçici dosyasına bir alt süreç olarak döngü çalışan/FIFO:
      • geçici değişken (vasat (kötü manuel başkalarının erişimine temizleme gerektirir): Gereksiz bellek işlem değiştirme (özel, sözdizimi destekli bir FIFO vakası, manuel temizleme gerektirmez); Greg's BashFAQ/020 uyarlanmıştır kodu):

        i=0 #`unset i` will error on `i' usage if the `nounset` option is set 
        while IFS= read -r -d $'\0' file; do 
            patharray[i++]="$(dirname "$file")" # or however you want to process each file 
        done < <(locate -b0 '\.git') 
        
    • Bash 4.2 yeni lastpipe seçeneği() kullanın - (bir alt süreç olarak vasat bir boru hattının son komutu çalışmaz: Küresel etkiye sahiptir)

+0

Son olarak, 'xargs' -0' ile birleştirildi. Mükemmel cevap. –

4

Bash, bir boru hattının tüm komutlarını ayrı SubShell s'de çalıştırır. while döngüsünü içeren bir alt kaplama sona erdiğinde, patharray değişkenine yaptığınız tüm değişiklikler kaybolur.

yapabilirsiniz ikisi de aynı alt kabuğa içinde bulunan böylece while döngü ve birlikte echo ifadesi basitçe grubu:

gitrepo() { 
    local pathname dir 
    local -a patharray 

    locate -b '\.git' | {      # the grouping begins here 
     while read pathname; do 
      pathname=$(dirname "$pathname") 
      if [[ "$pathname" != *.* ]]; then 
       patharray+=("$pathname")  # add the element to the array 
      fi 
     done 
     printf "%s\n" "${patharray[@]}"  # all those quotes are needed 
    }           # the grouping ends here 
} 

Alternatif olarak, bir boru gerekmez kodunuzu yapılandırmanın: kullanmak ProcessSubstitution (her şeyden

gitrepo() { 
    local pathname dir 
    local -a patharray 

    while read pathname; do 
     pathname=$(dirname "$pathname") 
     if [[ "$pathname" != *.* ]]; then 
      patharray+=("$pathname")  # add the element to the array 
     fi 
    done < <(locate -b '\.git') 

    printf "%s\n" "${patharray[@]}"  # all those quotes are needed 
} 
İlgili konular