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

31

Je me suis écrit un programme Linux programqui a besoin d'une expression régulière en entrée.

Je veux appeler le programme dans le bashshell et transmettre cette expression régulière en tant qu'argument de ligne de commande au programme (il existe également 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. Existe-t-il un moyen de passer l'expression en utilisant une sorte de caractères d'échappement ou de guillemets, etc.?

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

Christian
la source

Réponses:

27

Vous pouvez soit

  1. Échappez à chaque symbole spécial avec une barre oblique inverse (comme dans \[abc\]_\[x\|y\]) ou
  2. Citez deux fois l'intégralité de l'argument (comme dans "[abc]_[x|y]").

EDIT: Comme certains l' ont souligné, le dobleqouting n'empêche pas l'expansion des variables ni la substitution de commandes. Par conséquent, si votre expression régulière contient quelque chose qui peut être interprété par bash comme l'un d'entre eux, utilisez plutôt des guillemets simples .

antichris
la source
4
En bash, les guillemets doubles ne contournent pas les variables "$HOME"ou les paramètres d' extension "${USER:-root}", la substitution de commandes sous forme "$(date)"ou "`date`"l'expansion arithmétique, l'expansion de l' "$((1 + 2))"historique "!!"ou l'échappement de barre oblique inverse "\\". Utilisez plutôt des guillemets simples. Voir la page de manuel du manuel bash, la section intitulée "Quoting".
Flimm
25

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 devez intégrer un devis unique:

$ 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! ]
Flimm
la source
Tu as raison. +1
antichris
6

Par man bash

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

Une barre oblique inverse entre guillemets ( \ ) est le caractère d'échappement . Il conserve la valeur littérale du caractère suivant qui suit, à l'exception de <newline>. Si une paire \ <newline> apparaît et que la barre oblique inverse n'est pas elle-même citée, la \ <newline> est traitée comme une continuation de ligne (c'est-à-dire qu'elle est supprimée du flux d'entrée et effectivement ignorée).

La présence de caractères entre guillemets simples préserve la valeur littérale de chaque caractère dans les guillemets. Un guillemet simple ne peut pas apparaître entre guillemets simples, même lorsqu'il est précédé d'une barre oblique inverse.

Mettre des caractères entre guillemets conserve la valeur littérale de tous les caractères entre guillemets, à l'exception de $ , ` , \ et, lorsque l'expansion de l'historique est activée ,! . Les caractères $ et ` conservent leur signification particulière entre guillemets doubles. La barre oblique inverse conserve sa signification spéciale uniquement lorsqu'elle est suivie par l'un des caractères suivants: $ , ` , " , \ ou <nouvelle> . Un guillemet double peut être cité entre guillemets doubles en le précédant d'une barre oblique inverse. sera effectuée à moins qu'un! apparaissant entre guillemets est échappé à l'aide d'une barre oblique inverse. La barre oblique inverse précédant le ! n'est pas supprimé.

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 , avec des caractères d'échappement antislash remplacés comme spécifié par la norme C ANSI. Les séquences d'échappement de barre oblique inverse, si elles sont présentes, sont décodées comme suit:

       \ une      alerte (cloche)
        \ b      retour arrière
        \ e 
       \ E      un caractère d'échappement
        \ f      saut de page
        \ n      nouvelle ligne
        \ r      retour chariot
        \ t      onglet horizontal
        \ v      onglet vertical
        \\      barre oblique inverse
        \ '      guillemet simple
        \ "      guillemet double
        \ nnn    le caractère à huit bits dont la valeur est la valeur octale nnn
              (un à trois chiffres)
       \ x HH    le caractère à huit bits dont la valeur est la valeur hexadécimale HH
              (un ou deux chiffres hexadécimaux)
       \ u HHHH le caractère Unicode (ISO / IEC 10646) dont la valeur est
              la valeur hexadécimale HHHH (un à quatre chiffres hexadécimaux)
        \ U HHHHHHHH
              le caractère Unicode (ISO / IEC 10646) dont la valeur est
              la valeur hexadécimale HHHHHHHH (une à huit chiffres hexadécimaux)
        \ c x     un Control- x caractère

Le résultat étendu est guillemet simple, comme si le signe dollar n'était pas présent.

Une chaîne entre guillemets précédée d'un signe dollar ( $ " chaîne " ) entraînera la traduction de la chaîne en fonction des paramètres régionaux actuels. Si les paramètres régionaux actuels sont C ou POSIX , le signe dollar est ignoré. Si la chaîne est traduite et remplacée, le remplacement est entre guillemets.

Evan Carroll
la source
2

Vous pouvez utiliser une barre oblique inverse ( \) devant les caractères spéciaux pour les échapper comme ceci:

john @ awesome: ~ # echo \ &
&
John T
la source
2

Bien qu'il puisse ne pas être utile comme expression régulière, certaines séquences de caractères peuvent être interprétées comme des noms de variables Bash. Pour éviter cela et éviter de les développer, utilisez des guillemets simples au lieu de guillemets doubles:

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

Citez chaque argument séparément (s'ils ont besoin d'ê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
En pause jusqu'à nouvel ordre.
la source
1
program "[abc]_[x|y]"
program "[abc]_[x|y]" anotherargument
Witek
la source
0

Les échapper devrait fonctionner correctement:

  programm \[abc\]_\[x\|y\]
Policier
la source
0

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

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

  1. Les guillemets doubles, qui permettent encore une certaine interprétation ($ expand et `backticks`)
  2. Les guillemets simples, qui passent tout à travers littéralement

Parce qu'il $s'agit d'un caractère valide dans les expressions rationnelles (fin de ligne / tampon), vous souhaiterez probablement utiliser des guillemets simples pour contenir l'expression rationnelle, à moins que vous ne stockiez dans une variable. Si vous prenez des données arbitraires d'une personne non fiable, vous devrez remplacer 'par '"'"', puis encapsuler des guillemets simples.

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

Phil P
la source
C'est l'une des réponses les plus correctes ici (j'apprécie particulièrement les instructions de remplacement 'par '"'"'), mais elle n'est toujours pas correcte. [EST un caractère spécial à décortiquer, il est utilisé dans les caractères génériques lors de l'extension de chemin (ce que fait le shell pour tout ce qui n'est pas cité).
jpalecek
C'est spécial dans certains contextes, tels que l'indexation de variables ou pour la globalisation, mais vous pouvez toujours taper foo=a[b]et puis echo $fooet voir que la chaîne n'a pas besoin de guillemets. Tu as raison, j'étais trop bref.
Phil P
Si vous n'êtes pas chanceux, il y a un fichier abdans le répertoire courant, et foocontiendra alors abplutôt que a[b]. Citez vos crochets, mes amis.
clacke
(Pour plus de clarté: je cite (comme la réponse originale l'indiquait clairement, où je poussais pour la citation), et c'est un déraillement latéral que j'aborde). Cette affirmation m'a surpris, alors je l'ai testée. Ce n'est pas vrai dans zsh ou bash, mais c'est vrai dans BSD / bin / sh. C'est contre POSIX et c'est un comportement non standard, vous devrez donc citer pour le gérer. Dans zsh, vous pouvez également setopt glob_assignactiver ce comportement, donc la citation est la réponse la plus sûre.
Phil P