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

bash : comment passer les arguments de la ligne de commande contenant des caractères spéciaux

J'ai écrit moi-même un programme linux program qui a besoin d'une expression régulière comme entrée.

Je veux appeler le programme dans le shell bash et lui passer cette expression régulière comme argument de ligne de commande (il y a aussi d'autres arguments de ligne de commande). Une expression régulière typique ressemble à

[abc]\_[x|y]

Malheureusement, les caractères [, ], et | sont des caractères spéciaux dans bash. Ainsi, appeler

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

ne fonctionne pas. Y a-t-il un moyen de passer l'expression en utilisant une sorte de caractères d'échappement ou de guillemets, etc.

(Appeler program "[abc]\_[x|y] anotheragument" ne fonctionne pas non plus, car il interprète les deux arguments comme un seul).

Réponses (8)

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

Vous pouvez choisir entre

  1. Échapper à chaque symbole spécial avec une barre oblique inversée (comme dans \[abc\]_\[x\|y\]) ou
  2. Double-citer l'argument entier (comme dans "[abc]_[x|y]").

EDIT: Comme certains l'ont fait remarquer, le dobleqouting n'empêche pas l'expansion des variables ni la substitution des commandes. Par conséquent, si votre regex contient quelque chose qui peut être interprété par bash comme étant l'une de ces variables, utilisez des guillemets simples à la place.

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

Utilisez des guillemets simples. Les guillemets simples garantissent qu'aucun des caractères n'est interprété.

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

Il existe deux solutions si vous avez besoin d'intégrer un guillemet simple :

$ 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

Par man bash

Il existe trois mécanismes de citation : le caractère d'évasion, les guillemets simples et les guillemets doubles.

Une barre oblique inversée non citée ( ** ) est le caractère d'évasion. Elle préserve la valeur littérale du caractère suivant, à l'exception de <newline>. Si une paire ** <newline> apparaît, et que la barre oblique inverse n'est pas elle-même citée, le ** <newline> est traité comme une continuation de ligne (c'est-à-dire qu'il est supprimé du flux d'entrée et effectivement ignoré).

Le fait de mettre les caractères entre guillemets simples préserve la valeur littérale de chaque caractère à l'intérieur des guillemets. Une apostrophe ne peut pas être placée entre des apostrophes simples, même si elle est précédée d'une barre oblique inversée.

Le fait de mettre les caractères entre guillemets doubles préserve la valeur littérale de tous les caractères entre guillemets, à l'exception de $, ` , ** , and, when history expansion is enabled, **!. The characters $ and ` qui conservent leur signification particulière entre guillemets doubles. La barre oblique inversée ne conserve sa signification particulière que lorsqu'elle est suivie de l'un des caractères suivants : $ , ` , , ** , ou **<newline>. Une double citation peut être citée entre guillemets en la faisant précéder d'une barre oblique inversée. Si elle est activée, l'expansion de l'historique sera effectuée à moins qu'un ! apparaissant entre guillemets doubles ne soit échappé par une barre oblique inversée. La barre oblique inversée précédant le ! n'est pas supprimée.

Les paramètres spéciaux * et @ ont une signification particulière lorsqu'ils sont entre guillemets (voir PARAMÈTRES ci-dessous).

Les mots de la forme $‘ string sont traités spécialement. Le mot se développe en chaîne, les caractères en retrait étant remplacés comme spécifié par la norme ANSI C. Les séquences d'échappement backslash, si elles existent, sont décodées comme suit :

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

Le résultat développé est indiqué par une seule citation, comme si le signe du dollar n'avait pas été présent. 

Une chaîne de caractères à deux guillemets précédée du signe du dollar ( **$"** _string_ **"** ) entraînera la traduction de la chaîne de caractères selon la locale actuelle. Si la locale courante est **C** ou **POSIX** , le signe dollar est ignoré. Si la chaîne est traduite et remplacée, le remplacement se fait entre guillemets. **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

Le résultat développé est indiqué par une seule citation, comme si le signe du dollar n'avait pas été présent.

Une chaîne de caractères à deux guillemets précédée du signe du dollar ( $” string ) entraînera la traduction de la chaîne de caractères selon la locale actuelle. Si la locale courante est C ou POSIX , le signe dollar est ignoré. Si la chaîne est traduite et remplacée, le remplacement se fait entre guillemets.

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

Bien qu'elle puisse ne pas être utile comme regex, certaines séquences de caractères peuvent être interprétées comme des noms de variables Bash. Pour éviter que cela ne se produise et pour ne pas les faire développer, utilisez des apostrophes simples au lieu d'apostrophes doubles :

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

Citez chaque argument séparément (s'ils doivent être cités) afin qu'ils soient interprétés comme des arguments indépendants. Vous pouvez également utiliser des tableaux dans certains cas :

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

Vous pouvez utiliser une barre oblique inversée ( `Vous pouvez utiliser une barre oblique inversée ( ) devant les caractères spéciaux pour leur échapper de la sorte :

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

D'où vient ce modèle ? Est-il fixe ou provient-il d'un utilisateur ? Est-ce l'utilisateur qui invoque le script sur le système local, ou quelqu'un de distant ?

Vous utilisez des guillemets pour envelopper les données afin d'empêcher le shell de les interpréter. Il y a deux options :

  1. les guillemets, qui permettent encore une certaine interprétation ($expand et backticks)
  2. Les apostrophes simples, qui font tout passer littéralement par

Parce que $ est un caractère valide dans les regexps (fin de ligne/tampon), vous voulez probablement utiliser les apostrophes simples pour tenir la regexp, à moins que vous ne stockiez dans une variable. Si vous prenez des données arbitraires de quelqu'un qui n'est pas de confiance, vous devrez remplacer ' par '"'"' et les mettre entre guillemets simples.

Notez que [abc]_[x|y] semble correspondre à x ou y, alors qu'il correspond en fait à l'un des trois caractères xy|. Les crochets correspondent aux caractères à l'intérieur et seulement - pour les intervalles et un ^ au début pour la négation. Donc, [abc]_(x|y) pourrait être ce que vous vouliez dire, et les parenthèses sont les caractères qui sont spéciaux pour le shell. Les crochets ne sont pas spéciaux pour le shell, il semble juste qu'ils le soient. Les doubles crochets [[...]] sont spéciaux.

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

Leur évasion devrait bien se passer :

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