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

bash: come passare argomenti a riga di comando contenenti caratteri speciali

Mi sono scritto un programma linux program che ha bisogno di un'espressione regolare come input.

Voglio chiamare il programma nella shell bash e passare quell'espressione regolare come argomento della linea di comando al programma (ci sono anche altri argomenti della linea di comando). Una tipica espressione regolare assomiglia a

[abc]\_[x|y]

Purtroppo i caratteri [, ], e | sono caratteri speciali in bash. Quindi, chiamare

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

non funziona. C'è un modo per passare l'espressione usando una sorta di caratteri di escape o virgolette ecc.

(Anche chiamare program "[abc]\_[x|y] anotheragument" non funziona, perché interpreta i due argomenti come uno solo).

Risposte (8)

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

Puoi sia

  1. Sfuggire ad ogni singolo simbolo speciale con un backslash (come in \[abc\]_\[x\|y\]) o
  2. Citare due volte l'intero argomento (come in "[abc]_[x|y]").

EDIT: Come alcuni hanno fatto notare, il dobleqouting non impedisce l'espansione delle variabili né la sostituzione dei comandi. Quindi se la vostra regex contiene qualcosa che può essere interpretato da bash come uno di questi, usate invece gli apici singoli .

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

Usate le virgolette singole. Le virgolette singole assicurano che nessuno dei caratteri sia interpretato.

$ 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
'

Ci sono due soluzioni se avete bisogno di incorporare un apice singolo:

$ 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

Ci sono tre meccanismi di citazione: il carattere escape, gli apici singoli e gli apici doppi.

Un backslash non quotato ( ** ) è il carattere di escape. Conserva il valore letterale del prossimo carattere che segue, con l'eccezione di <newline>. Se appare una coppia ** <newline>, e il backslash non è quotato, il ** <newline> è trattato come una continuazione di linea (cioè, è rimosso dal flusso di input ed effettivamente ignorato).

Racchiudere i caratteri tra apici singoli conserva il valore letterale di ogni carattere all'interno degli apici. Un apice singolo non può trovarsi tra apici singoli, anche se preceduto da un backslash.

Chiudere i caratteri tra virgolette doppie conserva il valore letterale di tutti i caratteri all'interno delle virgolette, con l'eccezione di $ , ` , ** , and, when history expansion is enabled, **!. The characters $ and ` mantengono il loro significato speciale all'interno delle virgolette doppie. Il backslash mantiene il suo significato speciale solo se seguito da uno dei seguenti caratteri: $ , ` , , ** , o **<newline>. Un doppio apice può essere citato all'interno di doppi apici precedendolo con un backslash. Se abilitato, l'espansione della cronologia verrà eseguita a meno che un ! che appare tra virgolette doppie sia evaso con una barra rovesciata. Il backslash che precede il ! non viene rimosso.

I parametri speciali * e @ hanno un significato speciale quando sono tra doppi apici (vedi PARAMETRI più avanti).

Le parole della forma $‘ string sono trattate in modo speciale. La parola si espande a string, con i caratteri con escape backslash sostituiti come specificato dallo standard ANSI C. Le sequenze di escape backslash, se presenti, sono decodificate come segue:

**\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**  

Il risultato espanso è tra virgolette, come se il segno del dollaro non fosse stato presente. 

Una stringa tra virgolette preceduta dal segno del dollaro ( **$"** _string_ **"** ) farà sì che la stringa venga tradotta secondo il locale corrente. Se il locale corrente è **C** o **POSIX** , il segno del dollaro viene ignorato. Se la stringa viene tradotta e sostituita, la sostituzione è a doppi apici. **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

Il risultato espanso è tra virgolette, come se il segno del dollaro non fosse stato presente.

Una stringa tra virgolette preceduta dal segno del dollaro ( $” string ) farà sì che la stringa venga tradotta secondo il locale corrente. Se il locale corrente è C o POSIX , il segno del dollaro viene ignorato. Se la stringa viene tradotta e sostituita, la sostituzione è a doppi apici.

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

Anche se potrebbe non essere utile come regex, alcune sequenze di caratteri possono essere interpretate come nomi di variabili Bash. Per evitare che questo accada ed evitare che vengano espanse, usate virgolette singole invece che doppie:

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

Cita ogni argomento separatamente (se hanno bisogno di virgolette) in modo che siano interpretati come argomenti indipendenti. In alcuni casi potete anche usare degli array:

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

Potete usare una barra rovesciata ( `Potete usare una barra rovesciata ( ) davanti ai caratteri speciali per evadere come segue:

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

Da dove viene il modello? È fisso o viene da un utente? È l'utente che sta invocando lo script sul sistema locale, o qualcuno remoto?

Si usano le virgolette per avvolgere i dati per evitare che la shell li interpreti. Ci sono due opzioni:

  1. Doppie virgolette, che permettono ancora qualche interpretazione ($expand e backticks)
  2. Virgolette singole, che fanno passare tutto letteralmente

$ Perché ' è un carattere valido nelle regexp (fine riga/buffer) probabilmente volete usare le virgolette singole per contenere la regexp, a meno che non stiate memorizzando in una variabile. Se state prendendo dati arbitrari da qualcuno non fidato, avrete bisogno di sostituire '"'"' con [abc]_[x|y] e poi avvolgere in virgolette singole.

Notate che x sembra che voglia corrispondere a y o xy|, mentre in realtà corrisponde a uno dei tre caratteri -. Le parentesi quadre corrispondono ai caratteri all'interno e solo a ^ per gli intervalli e uno [abc]_(x|y) all'inizio per la negazione. Quindi, [[...]] potrebbe essere quello che intendevi, e le parentesi sono i caratteri che sono speciali per shell. Le parentesi quadre non sono non speciali per la shell, sembra solo che lo siano. Le parentesi quadre doppie 0x6& sono speciali.

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

L'escape dovrebbe funzionare bene:

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