Komut satırı bağımsız değişkenlerinde hangi karakterlerin kaçması gerekir?


14

Bash'te, bir komuta komut satırı bağımsız değişkenleri belirtirken, hangi karakterlerin kaçması gerekir?

Onlar Bash meta karakterlere sınırlıdır: Boşluk, sekme, |, &, ;, (, ), <, ve >?


* Ve ile dosya adını (ve) yutmayı unutma?
Jeff Schaller

Teşekkürler. Cmd satır argümanlarında kaçması gereken karakter türlerini kapsamlı bir şekilde listeleyebilir misiniz?
Tim

Listenin olması iyidir, ancak alıntı hakkında anlaşılması gereken en önemli şey şudur: Tek tırnaklar arasındaki her şey kelimenin tam anlamıyla ve kelime bölünmeden geçirilir. İstisna yok. (Bu, tek bir alıntıyı tek tırnak içine gömmenin hiçbir yolu olmadığı anlamına gelir, ancak bu arada, bu kolay bir şekilde çalışmaktır .)
Wildcard

Yanıtlar:


22

Aşağıdaki karakterlerin bazı bağlamlarda kabuğun kendisi için özel bir anlamı vardır ve bağımsız değişkenlerden kaçmaları gerekebilir:

Bu karakterlerden bazıları, bağladığım karakterden daha fazla şey ve daha fazla yerde kullanılıyor.


Açıkça isteğe bağlı birkaç köşe örneği vardır:

  • !set +Hetkileşimli olmayan kabuklarda varsayılan olan devre dışı bırakılabilir .
  • {ile devre dışı bırakılabilir set +B.
  • *ve ?ile devre dışı bırakılabilir set -fveyaset -o noglob .
  • =Eşittir işaretinin (U + 003D) set -kveyaset -o keyword etkinleştirilirse de kaçması gerekir .

Yeni satırdan kaçmak alıntı yapmak gerektirir - ters eğik çizgiler işi yapmaz. IFS'de listelenen diğer karakterlerin de benzer şekilde ele alınması gerekir. Kaçmak gerek yok ]ya }, ama do kaçmak gerekir )bir operatör olduğu için.

Bu karakterlerden bazıları, kaçmak gerektiğinde diğerlerinden daha sıkı sınırlara sahiptir. Örneğin a#b, tamam, ama a #bbir açıklama, >her iki bağlamda kaçmak gerekir. Zaten hepsinden muhafazakar bir şekilde kaçmak acı vermez ve ince ayrımları hatırlamaktan daha kolaydır.

Komut adınızın kendisi bir kabuk anahtar kelimesi ( ,, ) ifise for, dosizden de kaçmanız veya alıntı yapmanız gerekir. Bunlardan tek ilginç olanı, inbunun her zaman bir anahtar kelime olduğu açık değildir. Sen yok (! Aptalca) yalnızca olmasa da bunu, argümanları kullanılan anahtar kelimeler için bunu yapmak zorunda Bunlardan birinin peşine bir komut adını verdi. Kabuk operatörleri ( (, &vb.) Her zaman nerede olurlarsa olsun alıntı yapmaya ihtiyaç duyarlar.


1 Stéphane, bölgenizdeki herhangi bir tek baytlık boş karakterin de kaçması gerektiğini belirtti. En yaygın, mantıklı yerel ayarlarda, en azından C veya UTF-8 tabanlı olanlarda, yalnızca yukarıdaki boşluk karakteridir. Bazı ISO-8859-1 yerlerinde, Solaris, BSD'ler ve OS X dahil olmak üzere U + 00A0 kesintisiz alan boş kabul edilir (Yanlış düşünüyorum). Rastgele bilinmeyen bir yerle uğraşıyorsanız, harfler de dahil olmak üzere hemen hemen her şeyi içerebilir, iyi şanslar.

Muhtemelen, boş olmayan çok baytlık bir karakter içinde boş olarak kabul edilen tek bir bayt görünebilir ve her şeyi tırnak içine almaktan başka bir şeyden kaçamazsınız. Bu teorik bir endişe değildir: yukarıdan ISO-8859-1 yerel ayarında, A0boş olarak kabul edilen bayt, UTF-8 kodlu "à" ( ) gibi çok baytlı karakterler içinde görünebilir C3 A0. Bu karakterleri güvenli bir şekilde ele almak için onları alıntılamanız gerekir "à". Bu davranış, komut dosyasını yazdığınız ortamdaki yerel ayarlara bağlıdır; yazdığınız kod değil.

Bence bu davranış birden çok yönden kırıldı, ama ele aldığımız eli oynamak zorundayız. Kendiliğinden senkronize olmayan çok baytlı karakter kümeleriyle çalışıyorsanız, en güvenli şey her şeyi alıntılamak olacaktır. UTF-8 veya C'deyseniz (şimdilik) güvendesiniz.


Yerel ayarınızdaki diğer boşlukların da kaçması gerekir ( şu anda bir hata nedeniyle çok baytlı bir tanesi hariç )
Stéphane Chazelas

Yalnızca !komut dosyalarında değil, yalnızca csh geçmişi genişletmesi etkinleştirildiğinde kaçmanız gerekir . [ ! -f a ]ya find . ! -name...da iyi. Bu, daha sıkı sınırlar bölümünüz tarafından kapsanır, ancak açıkça belirtmeye değer.
Stéphane Chazelas

Diğer karakterler gibi alıntı gerek bağlamları vardır Not olun: hash[foo"]"]=, ${var-foo"}"}, [[ "!" = b ]], [[ a = "]]" ]], için regexp operatörleri [[ x =~ ".+[" ]]. Dışında anahtar kelimeler {( if, while, forbunlar gibi tanınmış değiliz yani ...) ... alıntı gerekecektir
Stéphane Chazelas

Bunlar komut satırı argümanları olduğu ölçüde, yorum söz konusu komuta kadar (tıpkı gibi ]), bu yüzden onları listelemiyorum. Herhangi bir anahtar kelimenin bağımsız değişken konumunda alıntı yapması gerektiğini düşünmüyorum.
Michael Homer

2
Yerleşik, tire veya% işaretinden alıntı yapmak hiçbir şey yapmaz.
Michael Homer

3

GNU Paralel'de bu test edilir ve kapsamlı olarak kullanılır:

$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'                                                                                                         
$a =~ s/[\n]/'\n'/go;

Bu test edilir bash, dash, ash, ksh, zsh, ve fish. Karakterlerin bazılarının kabukların bazılarında (versiyonlarında) alıntı yapmasına gerek yoktur, ancak yukarıdakiler test edilen tüm kabuklarda çalışır.

Sadece bir dize alıntı yapmak istiyorsanız, onu içine boru olabilir parallel --shellquote:

printf "&*\t*!" | parallel --shellquote

Daha önce nasıl paralel duymadım ...
Tom H

@TomH Size nasıl ulaşacağımızı düşünmek için 5 dakika harcayabilirseniz takdir edilecektir.
Ole Tange

Bence bu bir ilerleme sorunu. çoğu insan bazı karmaşıklık aşamalarında ilerleyene kadar paralelliğe ihtiyaç duymaz veya anlamaz. Bu sırada xargs, nohup ve bunun gibi şeylerle karşılaştılar. Ayrıca yığın değişiminde sorunları çözmek için paralel kullandığımda veya bash sorunlarına çözüm bulmak için google kullandığımda pek çok insan görmüyorum
Tom H

1

Perl'de hafif kaçan çözüm için, tek tırnak prensibini takip ediyorum. Tek tırnak içindeki bir Bash-string, tek tırnak dışında herhangi bir karakter içerebilir.

Kodum:

my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);

while(<>) {
    if (/$bash_reserved_characters_re/) {
        my $quoted = s/'/'"'"'/gr;
        print "'$quoted'";
    } else {
        print $_;
    }
}

Örnek çalışma 1:

$ echo -n "abc" | perl escape_bash_special_chars.pl
abc

Örnek çalışma 2:

echo "abc" | perl escape_bash_special_chars.pl
'abc
'

Örnek çalışma 3:

echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c

Örnek çalışma 4:

echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'

Örnek çalışma 5:

echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'

echo 'ab'"'"'c'
ab'c

Evet, geçerli bir nokta. Benim görüşüm, çoğu insanın bu sayfaya geleceği, çünkü çözmeleri gereken bir sorun var. Bunun ilginç bir akademik tartışma yarattığı için değil. Bu yüzden, biraz konu dışı olsa bile, çözümler sunmak ve bunların avantajlarını tartışmak istiyorum.
Jari Turkia

Kodum sadece Michael Homer'in cevabının bir uygulaması. Yaptıklarından daha fazla bilgi getirmek istemedim.
Jari Turkia
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.