2010-07-14 12:51:58 +0000 2010-07-14 12:51:58 +0000
32
32

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

Napisałem sobie program linuxowy program, który potrzebuje wyrażenia regularnego jako wejścia.

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

[abc]\_[x|y]

Niestety, znaki [, ] i | są znakami specjalnymi w bash. Tak więc wywołanie

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

nie działa. Czy istnieje sposób, aby przekazać wyrażenie za pomocą jakiegoś znaku ucieczki lub cudzysłowu itp.

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

Odpowiedzi (8)

29
29
29
2010-07-14 12:59:46 +0000

Możesz albo

  1. Uciec od każdego pojedynczego symbolu specjalnego za pomocą odwrotnego ukośnika (jak w \[abc\]_\[x\|y\]) albo
  2. Podwójny cudzysłów dla całego argumentu (jak w "[abc]_[x|y]").

EDIT: Jak niektórzy zauważyli, podwójne cytowanie nie zapobiega interpretacji zmiennych ani podstawianiu komend. Dlatego jeśli twój regex zawiera coś, co może być interpretowane przez bash jako jedno z tych, użyj pojedynczych cudzysłowów zamiast tego.

28
28
28
2011-10-21 12:19:50 +0000

Użyj pojedynczych cudzysłowów. Pojedyncze cudzysłowy zapewniają, że żaden z tych 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 musisz wstawić pojedynczy cudzysłów:

$ 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!]
```.
6
6
6
2010-07-15 06:09:18 +0000

Per man bash

Istnieją trzy mechanizmy cytowania: znak escape, cudzysłów pojedynczy i cudzysłów podwójny.

Niecytowany odwrotny ukośnik ( ** ) jest znakiem escape. Zachowuje on dosłowną wartość następnego znaku, z wyjątkiem .

Zawieranie znaków w pojedynczych cudzysłowach zachowuje dosłowną wartość każdego znaku wewnątrz cudzysłowu. Pojedynczy cudzysłów nie może występować pomiędzy pojedynczymi cudzysłowami, nawet gdy jest poprzedzony odwrotnym ukośnikiem.

Ujęcie znaków w cudzysłów zachowuje dosłowną wartość wszystkich znaków w cudzysłowie, z wyjątkiem $ , ` , ** , and, when history expansion is enabled, **!. The characters $ and ` zachowują swoje specjalne znaczenie w cudzysłowie. Odwrotny ukośnik zachowuje swoje specjalne znaczenie tylko wtedy, gdy występuje po nim jeden z następujących znaków: $ , ` , , **** lub <newline. Podwójny cudzysłów może być cytowany wewnątrz cudzysłowów przez poprzedzenie go odwrotnym ukośnikiem. Jeżeli jest włączona, to interpretacja historii będzie wykonywana, chyba że **! występujące w cudzysłowach zostanie usunięte przy pomocy odwrotnego ukośnika. Odwrotny ukośnik poprzedzający ! nie jest usuwany.

Parametry specjalne @ i @ mają specjalne znaczenie, gdy znajdują się w cudzysłowach (zobacz PARAMETRY poniżej).

Słowa w postaci $‘ string są traktowane specjalnie. Słowo interpretowane jest jako string, przy czym znaki odwrotnego ukośnika zastępowane są znakami określonymi przez standard ANSI C. Sekwencje ucieczki przed odwrotnym ukośnikiem, jeśli występują, są dekodowane w następujący sposób:

**\a** alert (bell) **\b** backspace **\e**** \E **an escape character** \f **form feed** \n **new line** \r **carriage return** \t **horizontal tab** \v **vertical tab** \ **backslash**  

Zinterpretowany wynik jest cytowany pojedynczo, tak jakby znak dolara nie występował. 

Podwójnie cytowany łańcuch poprzedzony znakiem dolara ( **$"** _string_ **"** ) spowoduje, że łańcuch zostanie przetłumaczony zgodnie z bieżącym locale. Jeśli bieżącym locale jest **C** lub **POSIX** , znak dolara jest ignorowany. Jeśli łańcuch zostanie przetłumaczony i zastąpiony, to zamiana jest cytowana podwójnie. **single quote** \" **double quote** \**_nnn_ the eight-bit character whose value is the octal value _nnn_ (one to three digits)**\x**_HH_ the eight-bit character whose value is the hexadecimal value _HH_ (one or two hex digits)**\u**_HHHH_ the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value _HHHH_ (one to four hex digits)**\U**_HHHHHHHH_ the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value _HHHHHHHH_ (one to eight hex digits)**\c**_x_ a control-_x_ character

Zinterpretowany wynik jest cytowany pojedynczo, tak jakby znak dolara nie występował.

Podwójnie cytowany łańcuch poprzedzony znakiem dolara ( $” string ) spowoduje, że łańcuch zostanie przetłumaczony zgodnie z bieżącym locale. Jeśli bieżącym locale jest C lub POSIX , znak dolara jest ignorowany. Jeśli łańcuch zostanie przetłumaczony i zastąpiony, to zamiana jest cytowana podwójnie.

2
2
2
2010-07-15 02:11:13 +0000

Chociaż może to nie być użyteczne jako regex, niektóre sekwencje znaków mogą być interpretowane jako nazwy zmiennych Bash. Aby temu zapobiec i uniknąć ich interpretacji, 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żna również używać 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
2
2
2
2010-07-14 12:57:29 +0000

Możesz użyć odwrotnego ukośnika ( `Możesz użyć odwrotnego ukośnika ( ) przed znakami specjalnymi, aby je uciec, jak poniżej:

john@awesome:~ # echo 0x1& &
1
1
1
2010-07-14 12:56:05 +0000
program "[abc]_[x|y]"
program "[abc]_[x|y]" anotherargument
0
0
0
2010-07-15 07:18:57 +0000

Skąd pochodzi ten wzór? Czy jest on stały, czy pochodzi od użytkownika? Czy jest to użytkownik, który wywołuje skrypt w systemie lokalnym, czy ktoś zdalny?

Używasz cudzysłowów do zawijania danych, by uniemożliwić powłoce ich interpretację. Istnieją dwie opcje:

  1. Cudzysłowy podwójne, które nadal pozwalają na pewną interpretację ($expand i backticks)
  2. Pojedyncze cudzysłowy, które przepuszczają wszystko dosłownie

Ponieważ $ jest poprawnym znakiem w regexpach (koniec linii/bufor), prawdopodobnie będziesz chciał użyć pojedynczych cudzysłowów do przechowywania regexpów, chyba że przechowujesz je w zmiennej. Jeśli pobierasz arbitralne dane od kogoś niezaufanego, będziesz musiał zastąpić ' przez '"'"', a następnie zawinąć w pojedyncze cudzysłowy.

Zauważ, że [abc]_[x|y] wygląda jakbyś chciał dopasować x lub y, podczas gdy w rzeczywistości jest to dopasowanie jednego z trzech znaków xy|. Nawiasy kwadratowe dopasowują znaki wewnątrz i tylko - dla zakresów i ^ na początku dla negacji. Tak więc, [abc]_(x|y) może być tym, co miałeś na myśli, a nawiasy są znakami, które są specjalne dla powłoki. Nawiasy kwadratowe nie są nie specjalne dla powłoki, po prostu wygląda na to, że są. Podwójne nawiasy kwadratowe [[...]] są specjalne.

0
0
0
2010-07-14 12:57:13 +0000

Ucieczka od nich powinna działać dobrze:

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