Bir değişkenin başka bir komut dosyasının içeriği olarak kullanılması


20

Bu soru, düzgün bir şekilde kaçak bir dize değişmezinin nasıl yazılacağı ile ilgili değildir . Bir komut dosyasında veya diğer programlarda doğrudan tüketim için değişkenlerden nasıl kaçacağı ile ilgili olmayan herhangi bir soru bulamadım.

Amacım başka bir komut dosyası oluşturmak için bir komut dosyasını etkinleştirmek. Bunun nedeni, oluşturulan komut dosyalarındaki görevlerin başka bir makinede 0 ila n arasında herhangi bir yerde çalışması ve oluşturuldukları verilerin (tekrar) çalıştırılmadan önce değişebilmesidir, bu nedenle işlemleri bir ağ üzerinden doğrudan yapmak çalışmıyor.

Böyle tek tırnak gibi özel karakterler içerebilir bilinen bir değişkeni göz önüne alındığında, örneğin bir değişken olarak tam çıkışı dize olarak dikkat yazmak gerekir fooiçeren bar'bazoluşturulan komut dosyası olarak görünmelidir:

qux='bar'\''baz'

"qux=$foo_esc"diğer senaryo satırlarına eklenerek yazılır . Perl kullanarak böyle yaptım:

foo_esc="'`perl -pe 's/('\'')/\\1\\\\\\1\\1/g' <<<"$foo"`'"

ama bu aşırıya kaçmış gibi görünüyor.

Bunu sadece bash ile yapmayı başaramadım. Bunların birçok varyasyonunu denedim:

foo_esc="'${file//\'/\'\\\'\'}'"
foo_esc="'${file//\'/'\\''}'"

ancak çıktıda fazladan eğik çizgiler görünür (yaptığımda echo "$foo") veya sözdizimi hatasına neden olurlar (kabuktan yapıldıysa daha fazla girdi beklenirler).


aliasve / veya setoldukça evrensel
mikeserv

@mikeserv Üzgünüz, ne demek istediğinden emin değilim.
Walf

alias "varname=$varname" varnameorvar=value set
mikeserv

2
@mikeserv Önerilerinizin ne yapması gerektiğini ya da herhangi bir değişkenden kaçmanın jenerik bir yöntemi olarak nasıl kullanacağımı anlamak benim için yeterli bir bağlam değil. Bu çözülmüş bir sorun, dostum.
Walf

Yanıtlar:


27

Bash, tam olarak bu durum için bir parametre genişletme seçeneğine sahiptir :

${parameter@Q}Genişletme, girdi olarak yeniden kullanılabilen bir biçimde alıntılanan parametrenin değeri olan bir dizedir .

Yani bu durumda:

foo_esc="${foo@Q}"

Bu Bash 4.4 ve sonraki sürümlerde desteklenir. Diğer genişletme biçimleri ve özel olarak tam atama ifadeleri ( @A) oluşturmak için de birkaç seçenek vardır .


7
Düzgün, ama sadece 4.2 veren verir bad substitution.
Walf

3
Z kabuğu eşdeğeri "${foo:q}".
JdeBP

Gerçekten hayatımı kurtar! "${foo@Q}"İşler!
hao

@JdeBP Z kabuk eşdeğeri çalışmıyor. Zsh için başka fikir var mı?
Steven Shaw

1
Cevabı buldum: "$ {(@ qq) foo}"
Steven Shaw

11

Bash, Bash'in eski (<4.0) sürümlerinde bile sizin için kabuk çıkışını gerçekleştiren bir format belirleyicisine printfsahip bir yerleşik sağlar %q:

printf '[%q]\n' "Ne'er do well"
# Prints [Ne\'er\ do\ well]

printf '[%q]\n' 'Sneaky injection $( whoami ) `ls /root`'
# Prints [Sneaky\ injection\ \$\(\ whoami\ \)\ \`ls\ /root\`]

Bu hile, bir işlevden veri dizilerini döndürmek için de kullanılabilir:

function getData()
{
  printf '%q ' "He'll say hi" 'or `whoami`' 'and then $( byebye )'
}

declare -a DATA="( $( getData ) )"
printf 'DATA: [%q]\n' "${DATA[@]}"
# Prints:
# DATA: [He\'ll\ say\ hi]
# DATA: [or\ \`whoami\`]
# DATA: [and\ then\ \$\(\ byebye\ \)]

Bash printfyerleşiminin printfçoğu Unix benzeri işletim sistemiyle birlikte gelen yardımcı programdan farklı olduğunu unutmayın . Herhangi bir nedenle, printfkomut yerleşik yerine yardımcı programı çağırırsa, bunun yerine her zaman çalıştırabilirsiniz builtin printf.


Elimden gerek olsaydın yardımcı olur emin nasıl değilim baskılı olurdu 'Ne'\''er do well', vb çıkışı dahil yani tırnak.
Walf

1
@Walf İki formun eşdeğer olduğunu ve her ikisinin de birbirleri kadar güvenli olduğunu anlamadığını düşünüyorum. Örneğin [[ 'Ne'\''er do well' == Ne\'er\ do\ well ]] && echo 'equivalent!'yankılanacakequivalent!
Dejay Clayton'a

Bunu özledim: P ancak sözdizimi vurgulayan bir görüntüleyicide / düzenleyicide okunması daha kolay olduğundan alıntılanan formu tercih ederim.
Walf

@Örnek, Perl örneğinizde, gereksiz önde gelen boş bir dize (ilk iki tek tırnak) ve uygun olmayan bir tek tırnak içeren 'hello'yanlış değerdeki sonuçlar gibi bir değer iletmek göz önüne alındığında, yaklaşımınızın oldukça tehlikeli olduğu görülmektedir ''\''hello''.
Dejay Clayton

1
@Walf, açıklama $'escape-these-chars'amacıyla , Bash'in belirtilen dize içindeki tüm karakterlerin kaçmasına neden olan ANSI-C alıntılama özelliğidir. Böylece, dosya $'first-line\nsecond-line')\n
adında

8

Sanırım RTFM yapmadım. Bu şekilde yapılabilir:

q_mid=\'\\\'\'
foo_esc="'${foo//\'/$q_mid}'"

Sonra echo "$foo_esc"beklenen verir'bar'\''baz'


Aslında nasıl kullanıyorum bir işlevi ile:

function esc_var {
    local mid_q=\'\\\'\'
    printf '%s' "'${1//\'/$mid_q}'"
}

...

foo_esc="`esc_var "$foo"`"

printfDejay'in çözümünün yerleşik özelliğini kullanmak için bunu değiştirmek :

function esc_vars {
    printf '%q' "$@"
}

3
Sürümüm desteklediğinde @ michael-homer'ın çözümünü kullanırdım.
Walf

4

Bir var değeri belirtmek için birkaç çözüm vardır:

  1. takma ad
    Çoğu kabuklarda (takma adın bulunduğu yerlerde) (csh, tcsh ve muhtemelen diğerleri gibi csh hariç):

    $ alias qux=bar\'baz
    $ alias qux
    qux='bar'\''baz'

    Evet, bu shçizgi veya kül gibi birçok kabukta çalışır .

  2. set
    çoğu kabukları (yine csh değil) da:

    $ qux=bar\'baz
    $ set | grep '^qux='
    qux='bar'\''baz'
  3. dizgi
    bazı kabukları (en azından Ksh, deneme ve zsh) 'de:

    $ qux=bar\'baz
    $ typeset -p qux
    typeset qux='bar'\''baz'             # this is zsh, quoting style may
                                         # be different for other shells.
  4. ihracat
    İlk yap:

    export qux=bar\'baz

    Sonra kullanın:
    export -p | grep 'qux=' export -p | grep 'qux='
    export -p qux

  5. alıntı
    echo "${qux@Q}"
    echo "${(qq)qux}" # bir ila dört q kullanılabilir.


Takma ad yaklaşımı zekidir ve POSIX tarafından belirtilmiş gibi görünür. Maksimum taşınabilirlik için bence bu yol. Ben önerileri içeren inanmak grepile exportveya setgömülü yeni satırlar içeren değişkenler üzerinde kırılabilir.
jw013
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.