Bash içindeki “eval” komutu nedir?


176

Bu evalkomutu ne yapabilirsin ? Neden faydalıdır? Bash'ta yerleşik bir fonksiyon mu? manSayfa yok ..


28
type commandBir komutun ne tür olduğunu öğrenmek için kullanın . ( type evalbu davada)
rozcietrzewiacz

9
"eval bir kabuk yerleşiktir"
Nuno Rafael Figueiredo

3
help evalkabuğundan "adam" sayfasını almak için
m-ric

eval bir bash yapılıdır ve bash'ın man sayfasında belgelenmiştir. Bu yüzden sadece "man bash" yazın ve eval için uygun bölümü arayın. Bu, diğer bash-builtin'ler için de geçerlidir.
Dirk Thannhäuser

Yanıtlar:


132

evalPOSIX'in bir parçasıdır. Yerleşik bir kabuk olabilen bir arayüz.

"POSIX Programcı El Kitabı" nda açıklanmıştır: http://www.unix.com/man-page/posix/1posix/eval/

eval - construct command by concatenating arguments

Bir argüman alacak ve bunun için kabuk tarafından yürütülecek bir komut oluşturacaktır. Manpage örneği budur:

1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
  1. İlk hat içinde tanımlamak $foodeğeri ile '10've $xdeğer ile 'foo'.
  2. Şimdi $yhangi dizeden oluşacağını tanımlayın '$foo'. Dolar işareti ile kaçılmalıdır '$'.
  3. Sonucu kontrol etmek için echo $y,.
  4. Sonuç dize olacak '$foo'
  5. Şimdi ödevi ile tekrarlıyoruz eval. İlk önce $xdizeye değerlendirecek 'foo'. Şimdi y=$foodeğerlendirilecek olan ifademiz var y=10.
  6. Bunun sonucu echo $yşimdi değerdir '10'.

Bu, birçok dilde yaygın bir fonksiyondur, örneğin Perl ve JavaScript. Daha fazla örnek için perldoc eval'e bir göz atın: http://perldoc.perl.org/functions/eval.html


4
Kabuk terminolojisinde, evalyerleşik bir işlevdir, bir işlev değildir. Uygulamada, yerleşikler, bir dil tanımına sahip olmayan, ancak tam olarak değil (denilen bir işlevi tanımlamaya yetecek kadar bükülürseniz görünür hale gelir) görünmeyen işlevler gibi davranırlar eval.
Gilles

thx, şu düzeltildi :-)
echox

4
Eval ve backticks `arasındaki fark nedir?
JohnyTex

5
Geri tepmeler başka bir kabuğun tamamını çalıştırmak için kısa yolludur, bu da komut dosyanızda çalışan başka bir bash / sh işlemi gerçekleştireceğiniz anlamına gelir.
Aaron R.

Neden echo $ y (evre 3) $ foo yerine foo'yu (10) geri getiriyor? (yani sadece $ + yerine foo = foo değeri)?
JohnDoea

60

Evet, evalbash iç komutudur, bu yüzden bashman sayfasında açıklanmıştır .

eval [arg ...]
    The  args  are read and concatenated together into a single com-
    mand.  This command is then read and executed by the shell,  and
    its  exit status is returned as the value of eval.  If there are
    no args, or only null arguments, eval returns 0.

Genellikle bir Komut Değiştirme ile birlikte kullanılır . Açık olmadan eval, kabuk çalışır yürütmek için değil, bir komut ikamesi sonucunu değerlendirmek onu.

Bir eşdeğerini kodlamak istediğinizi söyleyin VAR=value; echo $VAR. Kabuğun, aşağıdakilerin yazılarını işleme biçimindeki farkı not edin echo VAR=value:

  1. andcoz@...:~> $( echo VAR=value )
    bash: VAR=value: command not found
    andcoz@...:~> echo $VAR
    <empty line>
    

    Kabuk yürütmeye çalışırsa echove VAR=valueiki ayrı komutlar olarak. İkinci dize hakkında bir hata atar. Atama etkisiz kalır.

  2. andcoz@...:~> eval $( echo VAR=value )
    andcoz@...:~> echo $VAR
    value
    
    Kabuk iki dizgiyi birleştirir (birleştirir) echove VAR=valuebu tek birimi uygun kurallara göre ayrıştırır ve yürütür.

Son fakat en az değil, evalçok tehlikeli bir komut olabilir. evalGüvenlik sorunlarından kaçınmak için bir komuta yapılan girişler dikkatlice kontrol edilmelidir.


18

evalayrı bir dış komut değil, yalnızca kabuk ( bash) tarafından bilinen ve içten bir komut anlamına gelen bir kabuk yerleşik olduğu için bir man sayfasına sahip değildir . bashMan sayfasının ilgili kısmı şöyle diyor:

eval [arg ...]
    The args are read and concatenated together into a single command.  
    This command is then  read  and executed by the shell, and its exit 
    status is returned as the value of eval.  If there are no args, or only 
    null arguments, eval returns 0

Ek olarak, eğer çıktı ise help eval:

eval: eval [arg ...]
    Execute arguments as a shell command.

    Combine ARGs into a single string, use the result as input to the shell,
    and execute the resulting commands.

    Exit Status:
    Returns exit status of command or success if command is null.

evalgüçlü bir komuttur ve eğer onu kullanmak istiyorsanız, beraberinde gelebilecek olası güvenlik risklerinden kaçınmak için çok dikkatli olmalısınız .


16

Eval deyimi, kabuğa eval'ün argümanlarını komut olarak almalarını ve komut satırından geçirmelerini söyler. Aşağıdaki gibi bir durumda faydalıdır:

Komut dosyanızda bir değişkenin içine bir komut tanımlıyorsanız ve daha sonra bu komutu kullanmak istiyorsanız, eval kullanmalısınız:

/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >

3
Örneğinizin 4. satırındaki yorum yanlıştır: Bu, "Yukarıdaki komut işe yaramadı çünkü bash adında bir komut bulmaya çalıştı ls | more. Başka bir deyişle: Tek komut adı, boşluklar ve çizgi sembolünü içeren dokuz karakterden oluşuyordu. .
cfi

Tam olarak aynı şekilde davrandığını anladım. bash --version == GNU bash, sürüm 3.2.57 (1) - yayınlanma (x86_64-apple-darwin18)
Alexander Bird

10

Eval nedir?

eval, genellikle yerleşik olarak uygulanan bir kabuk komutudur.

POSIX'te "eval" girişindeki " 2.14. Özel Dahili Yardımcı Programlar" ın bir parçası olarak listelenmiştir . Yerleşik anlamı:

"Yerleşik" terimi, kabuğun yardımcı programı doğrudan çalıştırabileceğini ve onu aramaya gerek duymadığını belirtir.

Bu ne işe yarıyor?

Basit bir ifadeyle: bir giriş satırının iki kez ayrıştırılmasını sağlar .

Bunu nasıl yapıyor?

Kabuk, bir çizgiyi "işlemden geçirmek" için izleyen adımlar dizisine sahiptir. Sen olabilir Bu resim bakmak ve eval gider tek çizgi, arka solda, 1. adıma olduğunun farkında. Gönderen POSIX açıklaması :

2.1 Kabuk Giriş

  1. Kabuk girişini okur ....
  2. Kabuk girişi belirteçlere böler: kelimeler ve operatörler
  3. Kabuk, girişi basit ve bileşik komutlara ayrıştırır.
  4. Kabuk çeşitli açılımlar yapar (ayrı olarak) ...
  5. Kabuk, yeniden yönlendirme gerçekleştirir ve yeniden yönlendirme işleçlerini ve onların işleçlerini parametre listesinden kaldırır.
  6. Kabuk bir işlevi, yerleşik, çalıştırılabilir bir dosyayı veya komut dosyasını çalıştırır ...
  7. Kabuk isteğe bağlı olarak komutun çıkış durumunu tamamlamasını ve toplamasını bekler.

6. adımda yerleşik bir işlem gerçekleştirilecektir.
6. adımda, değerlendirme işlenen hattın 1. adıma geri gönderilmesine neden olur
. Uygulama sırasının geri döndüğü tek koşul budur.

Bu yüzden şunu söylüyorum: eval ile bir giriş satırı iki kez ayrıştırıldı .

Ayrıştırmanın iki kez etkileri.

İlk.

Ve anlamak için en önemli etki. Bir çizginin ilk kez gösterilmesinin bir sonucu, yukarıda gösterilen yedi kabuk basamağına maruz kalmasıdır . 4. adımda (açılımlar) , en son Alıntı Kaldırma olan tüm açılımları gerçekleştirmek için bir dizi adım da vardır :

Alıntı kaldırma her zaman en son yapılmalıdır.

Dolayısıyla, her zaman, kaldırılmış bir alıntı düzeyi vardır.

İkinci.

Bu ilk etkinin sonucu olarak, hattın ilave / farklı kısımları kabuk ayrıştırmaya ve diğer tüm adımlara maruz kalmaktadır.

Örnek.

İndirection.

Bu, dolaylı açılımların yürütülmesine izin verir:

a=b b=c    ;    eval echo \$$a            ### shall produce "c"

Neden? Çünkü ilk döngüde, ilk $alıntı yapılır.
Bu nedenle, kabuk tarafından genişlemeler için göz ardı edilir.
A $ismi ile bir sonraki "b" üretmek için genişletildi.
Ardından, ilk alıntı yapılmadan bir seviye alıntı yapılır $.
İlk döngünün sonu.

O zaman, ikinci döngüde dizgenin $bkabuk tarafından okunmasıdır.
Sonra "c" ye genişledi ve
argüman olarak verildi echo.

İlk döngüde hangi değerlendirmenin üreteceğini "görmek" için (yeniden değerlendirilmek üzere), echo kullanın. Veya argümanları açıkça gösteren herhangi bir komut / script / program:

$ a=b b=c
$ eval echo \$$a;
c

Ne olduğunu "görmek" için, eval ile eco'yu değiştirin:

$ echo echo \$$a
echo $b

Bir satırın tüm "kısımlarını" aşağıdakilerle göstermek de mümkündür:

$ printf '<%s> ' echo \$$a
<echo> <$b>

Bu örnekte, yalnızca bir yankı ve bir değişkendir, ancak daha karmaşık durumların değerlendirilmesinde yardımcı olduğunu unutmayın.

Bir düzeltme.

Şunu söylemek gerekir: Yukarıdaki kodda bir hata var, görebiliyor musunuz?
Kolay: bazı alıntılar eksik.

Nasıl? sorabilirsin. Basit, değişkenleri değiştirelim (kodu değil):

$ a=b b="hi     jk"
$ eval echo \$$a
hi jk

Kayıp boşlukları gördün mü?
Bunun nedeni, içindeki değerin $bkabuk tarafından bölünmüş olmasıdır.

Bu sizi ikna etmiyorsa, şunu deneyin:

$ a=b b="hi  *  jk"
$ eval echo \$$a              ### warning this will expand to the list  
                              ### of all files in the present directory.

Neden?

Eksik alıntılar. Doğru çalışması için (iç "$a"ve dış \"tırnak işaretleri ekleyin ).
Bunu dene (tamamen güvenli):

$ a=b b="hi      *       jk"
$ eval echo \" \$"$a" \"
hi      *       jk

Kılavuz hakkında:

Onun için adam sayfası yok.

Hayır, bunun için bağımsız bir adam sayfası yok. El ile arama man -f evalveya apropos evalgiriş bile göstermiyor.

İçeride bulunur man bash. Herhangi bir yerleşik olarak.
"SHELL BUILTIN KOMUTLARI" ve ardından "eval" için arama yapın.

Yardım almanın daha kolay bir yolu şudur: Kısaca help eval, yerleşiklerin yardımlarını görmek için bunu yapabilirsiniz .

Eval neden kötü denir?

Çünkü metni dinamik olarak koda bağlar.

Başka bir deyişle: argümanlarının listesini (ve / veya bu argümanların genişlemesini) yürütülen bir satıra dönüştürür. Herhangi bir nedenle, bir saldırgan tarafından bir argüman ayarlandıysa, saldırgan kodunu yürüteceksiniz.

Ya da daha da basit, eval ile bir veya birkaç argümanın değerini kimin tanımladığını söyleyeceksiniz:

Hadi, buraya oturun ve herhangi bir komut satırı yazın, bunu güçlerimle yürüteceğim.

Bu tehlikeli mi? Bu herkes için açık olmalı.

Eval için emniyet kuralı olmalıdır:
Sadece hangi değişkenlere eval yürütmek Eğer bu değer verdik.

Daha fazla ayrıntıyı burada okuyun .


10

evalEn yorumlanır dillerin (bir özelliğidir TCL, python, ruby...), sadece kabukları. Kodu dinamik olarak değerlendirmek için kullanılır.

Kabuklarda, kabuk yerleşik komutu olarak uygulanır.

Temel olarak, evalbir dizgeyi argüman olarak alır ve içindeki kodu değerlendirir / yorumlar. Kabuklarda, evalbirden fazla argüman alabilir, ancak evalyalnızca değerlendirilecek dizeyi oluşturmak için bunları birleştirir.

Çok güçlü çünkü kodu dinamik olarak oluşturabilir ve çalıştırabilirsiniz, C gibi derlenmiş dillerde yapamayacağınız bir şey

Sevmek:

varname=$1 varvalue=$2
eval "$varname=\$varvalue" # evaluate a string like "foo=$varvalue"
                           # which in Bourne-like shell language
                           # is a variable assignment.

Ancak eval, kabuk kodu olarak yorumlanmasının nedenlerinden dolayı , aktarılanların dinamik (harici olarak sağlanan) bölümlerini dezenfekte etmek önemlidir .

Örneğin, yukarıdaki halinde $1olduğu evil-command; var, evaldeğerlendirilmesi-sona ereceğini evil-command; var=$varvaluekabuk kodu ve daha sonra bu çalıştırın evil-command.

Kötülüğü evalgenellikle abartılı.

Tamam, tehlikeli, ama en azından tehlikeli olduğunu biliyoruz.

(Kabuk bağlı olarak) gibi temizlenmiş değil, diğer komutların bir çok bağımsız değişkenler içinde kabuk kodunu değerlendirecek [aka test, export, printf, GNU sed, awkve tabii ki sh/ bash/ perlve tüm tercümanlar ...

Örnekler (burada kullanılarak unameolarak evil-commandve $aharici olarak sağlıksız verileri sağlanır):

$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux

$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"

Linux
$ a=';uname'; sh -c "echo $a"

Linux

Bunlar sed, export... komutları daha tehlikeli olarak kabul edilebilirdi , çünkü eval "$var"içeriğin $varkabuk kodu olarak değerlendirilmesine neden olacağı açık olsa da, sed "s/foo/$var/"ya export "$var=value"da ya da ile açık değildir [ "$var" -gt 0 ]. Dangerosity aynıdır, ancak diğer komutlarda da gizlidir.


@BinaryZebra, bir değişkende bulunan bir dizgeden geçiriliyor sedgibi evalve her ikisi için de bu dizginin içeriği kabuk kodu olarak değerlendiriliyor, o sedkadar tehlikeli eval, demek istediğim de bu. (şimdiye kadar çalıştırılmayan) sediçeren bir dize geçiriliyor ve uname komutu çalıştırılarak sonlandırılıyor. Eval için gibi. Olarak şunları yapmanız Temizlenmemiş verilerinin geçirilmesi değiliz biz burada konuştuğumuz şey değil. unamesedsed 's/foo/$a/g'sed
Stéphane Chazelas

2

Bu örnek biraz ışık tutabilir:

#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"

Yukarıdaki betiğin çıktısı:

$VAR2
$VAR1
25

Katkınız için teşekkür ederiz, ancak, oldukları kadar eğlenceli, kullanma (biraz farklı) örneklerinden oluşan bir liste hazırlamakla gerçekten ilgilenmiyoruz eval. evalMevcut cevaplarda kapsanmayan , işlevselliğinin bazı temel, kritik yönlerinin olduğuna inanıyor musunuz ? Eğer öyleyse, o zaman açıklayın ve açıklamanızı göstermek için örneği kullanın. Lütfen yorumlara cevap vermeyin;  cevabınızı daha net ve daha eksiksiz hale getirmek için düzenleyin .
Scott
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.