15 votes

Comment puis-je vérifier les caractères verbatim d'une chaîne de commande bash ?

J'ai eu ce comportement étrange ce matin dans un terminal bash :

user@home:/home/user$ [ -f /etc/openvpn/client.conf ] && echo true
bash: [: missing «]»
user@home:/home/user$ [ -f /etc/openvpn/client.conf ] && echo true
true
  • La première commande était collé à partir d'un script édité avec gedit.
  • Le second était tapé directement dans le terminal.

Après quelques recherches, j'ai découvert que suppression du 30ème caractère (l'espace entre client.conf et "]") et le remplacer par un espace a permis à la commande de fonctionner à nouveau.

Ma supposition était juste : un personnage inconnu s'est glissé dans la commande mais la question est :

  1. Comment puis-je faire apparaître ces caractères dans le terminal afin de pouvoir déboguer la commande ? Et plus important encore :
  2. Comment puis-je éviter que cela ne se reproduise ?

BTW, j'exécute Ubuntu 18.04 / langue française, le script à partir duquel je colle la commande est dans une clé USB et peut avoir été édité sous Windows aussi.


Merci pour vos très bonnes réponses. Le mauvais caractère est un c2 a0 caractère UTF-8 à espace insécable. La question Comment supprimer le caractère spécial 'M-BM-' avec sed ? a un fait intéressant sur ce personnage.

Ce qui est étrange, c'est que le script est exempt de ce caractère. Je ne sais donc pas d'où il vient.

18voto

Steven Points 56939

Vous pourriez utiliser cat avec le -A option : du manuel :

   -A, --show-all
          equivalent to -vET
   -E, --show-ends
          display $ at end of each line
   -T, --show-tabs
          display TAB characters as ^I
   -v, --show-nonprinting
          use ^ and M- notation, except for LFD and TAB

Alors cat -A yourscrip.sh vous fera découvrir des personnages invisibles et étranges.

11voto

Attie Points 18031

Vous pouvez notamment examiner les caractères que vous essayez d'utiliser à l'aide d'un visualiseur ou d'un éditeur hexagonal. hexdump est une bonne option si vous êtes limité au terminal.

$ hexdump -Cv <<"EOF"
> [ -f /etc/openvpn/client.conf ] && echo true
> EOF
00000000  5b 20 2d 66 20 2f 65 74  63 2f 6f 70 65 6e 76 70  |[ -f /etc/openvp|
00000010  6e 2f 63 6c 69 65 6e 74  2e 63 6f 6e 66 20 5d 20  |n/client.conf ] |
00000020  26 26 20 65 63 68 6f 20  74 72 75 65 0a           |&& echo true.|
0000002d

Vous pouvez voir ici que le space , close-square-brace , space sont correctes - 0x20 , 0x5D , 0x20 .

Ces valeurs sont des codes ASCII, affichés en format hexadécimal . Toute valeur en dehors de la plage 0x20 - 0x7E n'est pas un " caractère imprimable " en ce qui concerne l'ASCII, et il est fort probable qu'il ne soit pas compatible avec les interfaces de ligne de commande.

Note : J'ai copié votre premier " brisé "pour l'utilisation dans le hexdump exemple ci-dessus, donc quelque chose a remplacé l pas un espace ASCII avec un espace ASCII entre votre source originale et votre question rendue.


Pour répéter cette opération, procédez comme suit :

  1. Type hexdump -Cv <<"EOF" et appuyez sur Enter
  2. Collez le texte que vous souhaitez utiliser
  3. Type EOF sur une ligne à part, et appuyez sur Enter

Les terminaux et les interfaces de ligne de commande ne gèrent pas bien les caractères spéciaux - comme vous l'avez découvert. Si vous ne faites pas très attention au formatage de vos documents, vous aurez également des problèmes avec Microsoft Word (et d'autres) qui utilise les caractères " citations intelligentes ", em-dashes, la liste est longue...

Voyez la différence : (le haut est " citations intelligentes ", le bas est " citations droites ")

example of smart quotes vs straight quotes

$ hexdump -Cv <<"EOF"
> “quoted string”
> EOF
00000000  e2 80 9c 71 75 6f 74 65  64 20 73 74 72 69 6e 67  |...quoted string|
00000010  e2 80 9d 0a                                       |....|
00000014

Ici, les guillemets ouverts ne sont pas une simple citation ASCII ( " ), mais sont un Unicode / UTF-8 série - 0xE2 , 0x80 , 0x9C , oder U+201C - que le terminal ne traitera pas comme on pourrait s'y attendre.

La suggestion de Kiwy de cat -A fait également l'affaire :

$ cat -A <<"EOF"
> “quoted string”
> EOF
M-bM-^@M-^\quoted stringM-bM-^@M-^]$

Note : lors de l'utilisation de echo "..." | hd vous avez une chance que bash substitue des parties de la chaîne que vous essayez d'inspecter. Ceci est particulièrement préoccupant lorsque vous essayez d'inspecter les composants d'un script.

Essayez par exemple :

$ echo "${USER}"
attie

$ echo "`whoami`"
attie

$ echo "$(whoami)"
attie

$ cat <<EOF
> ${USER}
> EOF
attie

Ces méthodes consistent à remplacer les composants par le texte correspondant. Pour éviter cela, utilisez l'une des approches suivantes. Notez l'utilisation de guillemets simples ( ' ), et un " cité heredoc " ( "EOF" ).

$ echo '${USER}'
${USER}

$ echo '`whoami`'
`whoami`

$ echo '$(whoami)'
$(whoami)

$ cat <<"EOF"
> ${USER}
> EOF
${USER}

9voto

xenoid Points 9208

echo "<your command>" | hd devrait fonctionner. Recherchez le retour arrière (0x08) ou les caractères dont le code est >=80. echo "<your command>" | wc -b et vérifier que le compte correspond à ce que vous voyez est également une bonne idée.

Il est dangereux de copier des éléments de fichiers produits par un logiciel ayant le mot "Office" dans son nom, car ces logiciels prennent souvent la liberté de remplacer des caractères : en français, attention aux guillemets, en anglais aux guillemets simples remplacés par leurs équivalents ouverts/fermés. Le plus difficile que j'ai trouvé était un espace insécable de largeur 0 au milieu d'un nom de fichier (3 jours d'arrêt du serveur...).

2voto

muru Points 1072

Bash, et d'autres shells comme zsh, peuvent ouvrir la ligne de commande actuelle dans un éditeur. Le raccourci par défaut de bash est C-x C-e ( CtrlX CtrlE ), et il s'ouvre dans le premier disponible de $VISUAL , $EDITOR et emacs. Dans la pratique, cela est inestimable pour déboguer et modifier des commandes complexes. Selon la façon dont vous le regardez, zsh est plus convivial que bash ici : lorsque l'éditeur quitte, bash exécute la commande immédiatement, alors que zsh attend que vous appuyiez sur Enter (ce qui vous donne plus de chances de modifier la commande).

Après avoir ouvert la commande dans un éditeur, vous pouvez configurer vos éditeurs pour qu'ils affichent différemment les caractères non ASCII.

Par exemple, avec Vim en utilisant ces paramètres :

set encoding=latin1
set isprint=
set display+=uhex

enter image description here

Ou encore, en adaptant les méthodes des autres réponses :

bash-4.4$ f() { cat -A "$@"; false; }   # exit false to prevent bash from running the command
bash-4.4$ VISUAL=f
bash-4.4$ [ -f /etc/openvpn/client.conf ] && echo true  # C-x C-e here
[ -f /etc/openvpn/client.confM-BM- ] && echo true$

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X