bash: jak przekazywać argumenty wiersza poleceń zawierające znaki specjalne

31

Napisałem sobie program linuksowy, programktóry wymaga wyrażenia regularnego jako danych wejściowych.

Chcę wywołać program w bashpowłoce i przekazać to wyrażenie regularne jako argument wiersza poleceń do programu (istnieją również inne argumenty wiersza poleceń). Wygląda typowe wyrażenie regularne

[abc]\_[x|y]

Niestety postacie [, ]i |są postaciami specjalnymi w bash. Tak więc dzwoniąc

program [abc]\_[x|y] anotheragument

nie działa Czy istnieje sposób na przekazanie wyrażenia za pomocą znaków specjalnych lub znaków cudzysłowu itp.?

(Wywołanie też program "[abc]\_[x|y] anotheragument"nie działa, ponieważ interpretuje dwa argumenty jako jeden.)

chrześcijanin
źródło

Odpowiedzi:

27

Możesz albo

  1. Unikaj każdego specjalnego symbolu odwrotnym ukośnikiem (jak w \[abc\]_\[x\|y\]) lub
  2. Cytuj dwukrotnie cały argument (jak w "[abc]_[x|y]").

EDYCJA: Jak niektórzy zauważyli, dobleqouting nie zapobiega rozszerzaniu zmiennych ani zastępowaniu poleceń. Dlatego jeśli wyrażenie regularne zawiera coś, co bash może zinterpretować jako jeden z nich, użyj pojedynczych cudzysłowów .

antychris
źródło
4
Bash dwukrotnie podając jest nie obejściowy rozszerza zmiennych "$HOME"lub parametrów "${USER:-root}", zastąpienie polecenia albo w postaci "$(date)"lub "`date`", arytmetycznego "$((1 + 2))"rozszerzalności historii "!!"lub odwróconą ucieczki "\\". Zamiast tego użyj pojedynczych cudzysłowów. Zobacz stronę manuala bash, rozdział zatytułowany „Cytowanie”.
Flimm,
25

Użyj pojedynczych cudzysłowów. Pojedyncze cudzysłowy zapewniają, że żaden ze znaków nie zostanie zinterpretowany.

$ printf %s 'spaces  are  not  interpreted away
neither are new lines
nor variable names $TESTING
nor square brackets [TESTING]
nor pipe characters or redirection symbols | > <
nor the semicolon ;
nor backslashes \a \b \c \\
the only thing that does not work is the single quote itself
'

Istnieją dwa rozwiązania, jeśli chcesz umieścić pojedynczy cytat:

$ printf '%s\n' '[ Don'"'"'t worry, be happy! ]'
[ Don't worry, be happy! ]
$ printf '%s\n' '[ Don'\''t worry, be happy! ]'
[ Don't worry, be happy! ]
Flimm
źródło
Masz rację. +1
antychris
6

Za man bash

Istnieją trzy mechanizmy cytowania: znak zmiany znaczenia , pojedyncze cudzysłowy i podwójne cudzysłowy.

Niecytowany ukośnik odwrotny ( \ ) to znak zmiany znaczenia . Zachowuje dosłowną wartość następnego następującego znaku, z wyjątkiem <nowej linii>. Jeśli pojawi się para \ <nowa linia>, a sam odwrotny ukośnik nie jest cytowany, \ <nowa linia> jest traktowana jako kontynuacja linii (to znaczy jest usuwana ze strumienia wejściowego i skutecznie ignorowana).

Umieszczanie znaków w pojedynczych cudzysłowach zachowuje dosłowną wartość każdego znaku w cudzysłowach. Pojedynczy cytat może nie wystąpić między pojedynczymi cudzysłowami, nawet jeśli poprzedzony jest odwrotnym ukośnikiem.

Załączając znaków w cudzysłowy chroni dosłowne wartości wszystkich znaków wewnątrz cudzysłowów, z wyjątkiem $ , ` , \ , a gdy ekspansja historia jest włączona ! . Znaki $ i ` zachowują swoje specjalne znaczenie w podwójnych cudzysłowach. Ukośnik odwrotny zachowuje swoje specjalne znaczenie tylko wtedy, gdy następuje po nim jeden z następujących znaków: $ , ` , " , \ lub <nowa linia> . Podwójny cudzysłów można cytować w podwójnych cudzysłowach, poprzedzając go odwrotnym ukośnikiem. Jeśli jest włączony, rozszerzenie historii zostaną wykonane, chyba że! występowanie w podwójnych cudzysłowach jest poprzedzane znakiem odwrotnego ukośnika. Odwrotny ukośnik poprzedzający ! nie jest usuwany.

Parametry specjalne * i @ mają specjalne znaczenie w cudzysłowach (patrz PARAMETRY poniżej).

Słowa w postaci $ „ string są traktowane specjalnie. Słowo jest interpretowane jako ciąg znaków , z zastąpionymi znakami odwrotnego ukośnika zgodnie ze standardem ANSI C. Sekwencje specjalne odwrotnego ukośnika, jeśli są obecne, są dekodowane w następujący sposób:

       \ a      alarm (dzwon)
        \ b      cofania
        \ e 
       \ e      charakter ucieczki
        \ f      wysuwu
        \ n      nowej linii
        \ r      karetki
        \ t      poziomej zakładka
        \ v      karta pionowe
        \\      ukośnikowe
        \”      apostrof
        \”      podwójnie cytat
        \ nnn    ośmiobitowy znak, którego wartość jest wartością ósemkową nnn
              (od jednej do trzech cyfr)
       \ x HH    ośmiobitowy znak, którego wartością jest wartość szesnastkowa HH
              (jedna lub dwie cyfry szesnastkowe)
       \ u hhhh się (10646 ISO / IEC) znak Unicode, którego wartość jest
              wartość szesnastkowa HHHH (jedna do czterech cyfr szesnastkowych)
        \ U HHHHHHHH
              znak Unicode (ISO / IEC 10646), którego wartość wynosi
              wartość szesnastkowa HHHHHHHH (od jednej do ośmiu cyfr szesnastkowych)
        \ c x     kontrola- znak x

Rozwinięty wynik jest cytowany pojedynczo, tak jakby znak dolara nie był obecny.

Ciąg cudzysłowu poprzedzony znakiem dolara ( $ „ ciąg ) spowoduje, że zostanie on przetłumaczony zgodnie z bieżącymi ustawieniami narodowymi. Jeśli bieżące ustawienia narodowe to C lub POSIX , znak dolara jest ignorowany. Jeśli ciąg zostanie przetłumaczony i zastąpiony, zamiennik zostanie podany w cudzysłów.

Evan Carroll
źródło
2

Możesz użyć odwrotnego ukośnika ( \) przed znakami specjalnymi, aby uciec przed nimi:

John @ awesome: ~ # echo \ &
I
John T.
źródło
2

Chociaż może to nie być przydatne jako wyrażenie regularne, niektóre sekwencje znaków mogą być interpretowane jako nazwy zmiennych Bash. Aby temu zapobiec i uniknąć rozszerzenia, użyj pojedynczych cudzysłowów zamiast podwójnych:

program '[abc]_[x|y]' anotherargument

Cytuj każdy argument osobno (jeśli wymagają cytowania), aby były interpretowane jako niezależne argumenty. W niektórych przypadkach możesz także użyć tablic:

param_array=('[abc]_[x|y]' anotherargument)    # create an array
param_array+=(yetanother)     # append another element to the array
program "${param_array[@]}"   # use the array elements as arguments to program
Wstrzymano do odwołania.
źródło
1
program "[abc]_[x|y]"
program "[abc]_[x|y]" anotherargument
Witek
źródło
0

Ucieczka przed nimi powinna działać dobrze:

  programm \[abc\]_\[x\|y\]
Konstabl
źródło
0

Skąd wziął się wzór? Czy to jest ustalone czy pochodzi od użytkownika? Czy to użytkownik wywołuje skrypt w systemie lokalnym, czy ktoś zdalny?

Używasz cudzysłowów do zawijania danych, aby powłoka nie mogła ich interpretować. Istnieją dwie opcje:

  1. Podwójne cudzysłowy, które wciąż pozwalają na pewną interpretację ($ expand i `backticks`)
  2. Pojedyncze cudzysłowy, które dosłownie przekazują wszystko

Ponieważ $jest poprawnym znakiem w wyrażeniach regularnych (koniec wiersza / bufor), prawdopodobnie chcesz użyć pojedynczych cudzysłowów do przechowywania wyrażenia regularnego, chyba że zapisujesz w zmiennej. Jeśli bierzesz dane z dowolnego ktoś zaufany, trzeba wymienić 'z '"'"'czym zawinąć w pojedynczych cudzysłowach.

Pamiętaj, że [abc]_[x|y]wygląda tak, jakbyś chciał dopasować xlub y, podczas gdy w rzeczywistości pasuje do jednego z trzech znaków xy|. Nawiasy kwadratowe pasują do znaków wewnątrz i tylko -dla zakresów i a ^na początku dla negacji. Tak, [abc]_(x|y)może być to, co myśli, i nawiasy są znaki, które są szczególne dla Shell. Nawiasy kwadratowe nie są specjalne dla powłoki, po prostu wygląda tak, jak są. Podwójne nawiasy kwadratowe [[ ... ]]są wyjątkowe.

Phil P.
źródło
Jest to jeden z najbardziej poprawnych odpowiedzi tutaj (doceniam zwłaszcza dyspozycję do wymiany 'z '"'"'), jednak nadal nie jest poprawna. [JEST specjalnym znakiem do powłoki, jest używany w symbolach wieloznacznych podczas ekspansji ścieżki (która powłoka robi dla wszystkiego, co nie jest cytowane).
jpalecek
Jest wyjątkowy w niektórych kontekstach, takich jak indeksowanie zmiennych lub globbing, ale nadal możesz pisać, foo=a[b]a potem echo $foosprawdzać, czy łańcuch nie wymaga cytowania. Masz rację, byłem zbyt krótki.
Phil P
Jeśli masz pecha, abw bieżącym katalogu znajduje się plik , który foobędzie zawierał abzamiast a[b]. Podaj swoje nawiasy kwadratowe, ludzie.
clacke
(Dla jasności: cytuję (jak wyjaśniono w pierwotnej odpowiedzi, gdzie naciskałem na cytowanie), i to jest wykolejenie boczne, do którego się zwracam). To stwierdzenie mnie zaskoczyło, więc to przetestowałem. Nie jest to prawdą w Zsh ani Bash, ale jest prawdą w BSD / bin / sh. Jest to sprzeczne z POSIX i jest niestandardowe, więc musisz się zacytować, aby sobie z tym poradzić. W Zsh możesz również setopt glob_assignwłączyć to zachowanie, więc cytowanie jest najbezpieczniejszą odpowiedzią.
Phil P