Değişkende depolanan bir komutu yürütme


11

Bir değişkende depolanan bir komut var. Değişkenin $işu değere sahip olduğunu varsayalım :

cat -nT index.php |grep 'someregex'

Yukarıdaki değişkeni yazmaya $içalıştığımda, kabuk tüm değişkeni tek bir komut olarak yürütmeye çalıştığından başarısız olur. Ben de kullanmak eval($i)ve $ibackticks koyarak denedim .

Kabuğun bir komutmuş $igibi çalıştırılmasını nasıl sağlayabilirim ? Ve neden olduğu gibi çalışmıyor.

$i='echo hi'; $i

Tek tırnak içinde kesmek zorunda olduğum için mi? (Çünkü onları iç içe geçiremezsiniz.) Şu anda benim çözümüm

echo $i > /foo;  . /foo

Ama sadece bunun için bir dosya oluşturmak istemiyorum, sadece daha sonra silmek için.

Demek istediğim "Ben tek tırnak hack ben yaptım:

$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"

4
Soru şu: Komut neden ilk etapta bir değişkende saklanıyor? Komutu çalıştırdığınızda, seçenek bağımsız değişkenlerini değişkenlerde veya bir dizide depolamaktansa iyi olur. Sahip olduğunuz komut dosyasının tamamını gösterebilir misiniz?
slhck

Yanıtlar:


18

Kısa cevap: bkz. BashAQ # 50: Bir değişkene komut koymaya çalışıyorum, ancak karmaşık durumlar her zaman başarısız! .

Uzun cevap: Bunun nedeni bash komut satırını ayrıştırma sırasıdır. Özellikle, değişken değerleri genişletmeden önce borular ve yönlendirmeler gibi şeyleri arar ve genişletilmiş değerlerde geri dönüp boruları vb. Aramaz. Temel olarak, değişkenler ayrıştırma işleminin yaklaşık yarısında ikame edilir, bu nedenle değer yürütülmeden önce yalnızca yarı yarıya ayrılır.

Bunu çözmek için @ slhck'in sorusuna cevap vermelisiniz: komut neden ilk başta bir değişkende saklanıyor? Çözmeye çalıştığınız asıl sorun nedir? Asıl hedefe bağlı olarak, bir dizi olası çözüm vardır:

  • Bir değişkende saklamayın, doğrudan yürütün. Komutları daha sonra kullanmak için saklamak zordur ve gerçekten ihtiyacınız yoksa, yapmanız gerekmez.

  • Değişken yerine bir işlev kullanın. Ne de olsa onlar için:

    i() { cat -nT index.php |grep 'someregex'; }
    i

    Bunun ana dezavantajı, işlevi dinamik olarak oluşturamamanızdır - koşullu olarak kodu işleve dahil edemez veya hariç tutamazsınız (işlevin kendisi yürütüldüğünde seçilen koşullu öğelere sahip olsa da).

  • Kullanın eval. Bu son çare olarak düşünülmelidir, çünkü beklenmedik davranışlar elde etmek kolaydır. Komutu başka bir tam ayrıştırma geçişi yoluyla çalıştırır, bu nedenle tüm borular vb. Kabuk metakarakterleri (boru, noktalı virgül, alıntı / kesme işareti vb.) İçeren dosya adlarının garip ve bazen tehlikeli etkileri olabilir. Eğer kullanımını yaparsanız eval, en azından daha da garip sonuçlarla, aksi içeriği esasen tek-ve-bir buçuk kat ayrıştırılır olsun, dize çift alıntı.

    i="cat -nT index.php |grep 'someregex'"
    eval "$i"

DÜZENLEME: Diğer bir standart-mağaza-bir-komut-sakla yaklaşımı, basit bir değişken yerine bir dizi kullanmaktır. Bu, komutları karmaşık bağımsız değişkenlerle (örn. Boşluk içeren) sorunsuz bir şekilde depolamanızı sağlar, ancak kanallar ve yönlendirmeler gibi şeyleri depolamaz. Bu nedenle, dizi yaklaşımı bu özel durumda yararlı olmaz.


evalYöntem için +1 . Bu da aynı soruyu sormamı engelledi :). sudo rsync -aAHXi -n --delete-excluded --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/lost+found","/mnt/DATA/*","/var/log/*","/var/swap","/var/cache/apt/archives/*.deb"} -e ssh root@piac_wireless:/ /home/mrx/Docs/RPi/backup/piac/piac_usb-rootİstisnaları doğru bir şekilde yerine getirmeyen böyle bir şeyim var .
dentex

@dentex Bunun evaliçin kullanmamanızı şiddetle tavsiye ederim - yanlış gitmesi için çok fazla yol var. Bir dizi bunu yapmanın daha iyi bir yolu olacaktır. Bkz burada , burada ve burada örnekler için.
Gordon Davisson

Önerin için teşekkürler. Hariç tutma listesini rsync'e geçirmek için çözümü diziyle uygulamaya çalışacağım.
dentex

4

Bu sadece işe yaramalıdır:

a="cat -nT index.php |grep 'someregex'"
eval "$a"

evalOlası güvenlik açıklarını ve beklenmedik davranış durumlarını ortaya çıkardığına dikkat edin, bu nedenle, eğer varsa, çok dikkatli kullanılmalıdır.


Kullanırsanız eval, eval "$i"ekstra garip efektlerden kaçınmak için gerçekten çift tırnak ( ) kullanmanız gerekir . Örneğin, bunu deneyin a="cat -nT index.php |grep ' .* '"(yani normal ifade, aralarındaki herhangi bir karakter dizisiyle iki boşluğu eşleştirmelidir) ve gerçekte ne olduğunu görün. Ekstra kredi için neden olduğunu açıklayın .
Gordon Davisson

@ GordonDavisson çift tırnak eklendi.
jlliagre

2

Değişkeni bildirirken dolar işaretini önek olarak kullanmamalısınız.

Bunu dene:

i='echo hi'; $i

1
Bu doğru, ama bu OP'nin sorusuna gerçekten bir cevap değil.
13:29, slhck

benim için
REALY
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.