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.)

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 .


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! ]

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.


2

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

John @ awesome: ~ # echo \ &
I

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

1
program "[abc]_[x|y]"
program "[abc]_[x|y]" anotherargument

0

Ucieczka przed nimi powinna działać dobrze:

  programm \[abc\]_\[x\|y\]

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.