Alıntılanan parametreleri almak ve yeniden onaylamak için Bash betiği


98

İç içe geçmiş bir komut dosyası tarafından güvenli bir şekilde alınacak bir bash betiğinin alıntı parametrelerini almaya çalışıyorum. Herhangi bir fikir?

test.sh

#!/bin/bash
echo $*
bash myecho.sh $*

myecho.sh

#!/bin/bash
 echo $1
 echo $2
 echo $3
 echo $4

Örneklem:

bash test.sh aaa bbb '"ccc ddd"'

Sonuç:

aaa bbb "ccc ddd"
aaa
bbb
"ccc
ddd"

İstenen sonuç

aaa bbb "ccc ddd"
aaa
bbb
ccc ddd

2
Ben de tam o soruyu soracaktım! İyi zamanlama.
Scottie T

Yanıtlar:


70
#!/bin/bash
echo $*
bash myecho.sh "$@"

"$ @" Yapısının bash'a özgü olmadığını ve herhangi bir POSIX kabuğu ile çalışması gerektiğini unutmayın (en azından tire ile çalışır). Ayrıca, istediğiniz çıktı verildiğinde, fazladan alıntı yapmaya hiç ihtiyacınız olmadığını unutmayın. IE yukarıdaki komut dosyasını şöyle çağırır:

./test.sh 1 2 "3 4"

5
"$ @", Korn ve Bash dahil olmak üzere herhangi bir Bourne kabuğu veya Bourne kabuğu türevi (1978'den itibaren) ile çalışır. Muhtemelen zamanın% 95'inde "$ @" kullanmak doğrudur ve $ * yanlıştır.
Jonathan Leffler

Güzel! Ancak, onu bir değişkende "olduğu gibi" saklamanın herhangi bir yolu olup olmadığını tanıyor musunuz ? Orijinal $@bir işlev içinde kullanılamaz (çünkü işlev bağımsız değişkenleri tarafından üzerine yazılmıştır). foovar="$@"foovar=$@"$foovar"
İşlevde

143

Parametreleri bir alt simgeye geçirmek için "$ @" (dolar cinsinden alıntı) kullanmak istiyorsunuz. Gibi ...

ls-color.sh:

#!/bin/bash
/bin/ls --color=auto "$@"    # passes though all CLI-args to 'ls'


Neden ...

Gönderen Bash adam sayfası :

$*- Birinden başlayarak konumsal parametrelere genişler. Genişleme çift tırnak içinde gerçekleştiğinde, IFS özel değişkeninin ilk karakteriyle ayrılmış her parametrenin değeriyle tek bir kelimeye genişler. Yani, "$*"eşdeğerdir "$1c$2c..." , burada c, IFS değişkeninin değerinin ilk karakteridir. IFS ayarlanmamışsa, parametreler boşluklarla ayrılır. IFS null ise, parametreler ayırıcılara müdahale edilmeden birleştirilir.

$@- Birinden başlayarak konumsal parametrelere genişler. Açma çift tırnak içinde gerçekleştiğinde, her parametre ayrı bir kelimeye genişler. Yani, "$@"şuna eşdeğerdir: "$1" "$2" ...Çift tırnaklı genişletme bir sözcük içinde meydana gelirse, ilk parametrenin genişletmesi orijinal sözcüğün başlangıç ​​kısmıyla birleştirilir ve son parametrenin genişletmesi, orijinalin son kısmıyla birleştirilir. kelime. Konumsal parametreler olmadığında "$@"ve $@hiçbir şeye genişlemediğinde (yani kaldırılırlar).


Bazı demo komut dosyaları oluşturma ...

echo 'echo -e "\$1=$1\n\$2=$2\n\$3=$3\n\$4=$4"' > echo-params.sh
echo './echo-params.sh $*' > dollar-star.sh
echo './echo-params.sh $@' > dollar-at.sh
echo './echo-params.sh "$*"' > quoted-dollar-star.sh
echo './echo-params.sh "$@"' > quoted-dollar-at.sh
chmod +x *.sh

"$@"- alıntılanan dolar, bağımsız değişkenleri bir alt kabuğa yeniden geçirmek için bir kimlik dönüşümüdür (zamanın ~% 99'u, yapmak istediğiniz şeydir):

./quoted-dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2=            
  # $3= 'cc cc'
  # $4= "ddd ddd"

"$*"- alıntılanan dolar-yıldız bağımsız değişkenleri tek bir dizeye böler (bu davranışı gerçekten istediğiniz zamanın ~% 1'i, örneğin bir koşulda:if [[ -z "$*" ]]; then ... :

./quoted-dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa  'cc cc' "ddd ddd"   
  # $2=                     
  # $3=             
  # $4=

$*/ $@- tırnak işaretleri olmadan, her iki form da bir düzey alıntıyı çıkarır ve temeldeki dizelerden boşlukları yorumlar ancak tırnak karakterlerini yok sayar (hemen hemen her zaman, bu bir hatadır):

./dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc                  
  # $3= cc'
  # $4= "ddd

./dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc
  # $3= cc'
  # $4= "ddd

Biraz eğlenmek istiyorsanız, istediğiniz kadar derine yerleştirmek için "$ @" kullanabilirsiniz, isterseniz öğeleri bağımsız değişken yığınından çıkarabilir ve kaldırabilirsiniz.

function identity() {
  "$@"
}
set -x
identity identity identity identity identity echo Hello \"World\"
# + identity identity identity identity identity echo Hello '"World"'
# + identity identity identity identity echo Hello '"World"'
# + identity identity identity echo Hello '"World"'
# + identity identity echo Hello '"World"'
# + identity echo Hello '"World"'
# + echo Hello '"World"'
# Hello "World"

1
Açıklama için teşekkürler. Grep takma adı için sadece "$ *" kullanıldı.
darkless

Günümü kurtardın!
xyz
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.