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

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

Advertisement

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

Advertisement
Advertisement

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
Advertisement
6
6
2010-07-15 06:09:18 +0000
Advertisement

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
Advertisement
2
2
2010-07-14 12:57:29 +0000
Advertisement

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
Advertisement
0
0
2010-07-15 07:18:57 +0000
Advertisement

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\]
Advertisement

Pytania pokrewne

6
10
11
7
8
Advertisement
Advertisement