Tuve este comportamiento extraño esta mañana en una terminal de 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
- El primer comando fue pegado de un script editado con gedit.
- El segundo fue escrito directamente en la terminal.
Después de investigar un poco, descubrí que al eliminar el carácter 30 (el espacio entre client.conf y "]") y reemplazarlo con un espacio, el comando funciona nuevamente.
Mi suposición era correcta: un carácter en blanco desconocido se deslizó en el comando , pero la pregunta es:
- ¿Cómo puedo revelar esos caracteres en la terminal para poder depurar el comando? Y más importante:
- ¿Cómo puedo evitar que esto vuelva a suceder?
Por cierto, ejecuto Ubuntu 18.04 / idioma francés, el script desde el que pego el comando está en una unidad USB y puede que también haya sido editado en Windows.
Gracias por tus muy buenas respuestas. El carácter incorrecto es un carácter UTF-8 de espacio c2 a0 que no se rompe. La pregunta Cómo eliminar el carácter especial 'M-BM-' con sed tiene un hecho interesante sobre ese personaje.
Lo extraño es que el guión está libre de este personaje. Entonces no sé de dónde vino.
fuente
history 2|xxd
(porque elhistory
comando en sí siempre es el último en la lista), o escribahistory|grep "CommandWithProblem"|xxd
. Puede usar cualquier otro programa de visualización hexadecimal en lugar dexxd
, pero esto por defecto es un formato que me gusta.set -x
. Esto le mostrará el comando y cómo se divide. No necesariamente diría "mal personaje aquí", pero te mostraría que bash no se estaba dividiendo en ese personaje.Respuestas:
Una opción es mirar los caracteres que está intentando usar con un visor o editor hexadecimal.
hexdump
es una buena opción si está limitado al terminal.Se puede ver aquí que el
space
,close-square-brace
,space
son correctas -0x20
,0x5D
,0x20
.Estos valores son códigos ASCII, que se muestran en hexadecimal . Cualquier valor fuera del rango
0x20
-0x7E
no es un " carácter imprimible " en lo que se refiere a ASCII, y lo más probable es que no va a jugar bien con interfaces de línea de comandos.Nota: Copié su primera línea " rota " para usar en el
hexdump
ejemplo anterior, por lo que algo ha reemplazado el espacio no ASCII con un espacio ASCII entre su fuente original y su pregunta representada.Para repetir esto, siga los siguientes pasos:
hexdump -Cv <<"EOF"
y presionaEnterEOF
en una línea propia y presioneEnterLos terminales y las interfaces de línea de comandos no manejan bien los caracteres especiales, como ha descubierto. Si no tiene mucho cuidado con el formato de los documentos, también tendrá problemas con Microsoft Word (y otros) al usar " comillas inteligentes ", guiones, la lista continúa ...
Encuentra la diferencia: (la parte superior es " comillas inteligentes ", la parte inferior es " comillas rectas ")
En este caso, las cotizaciones abiertas no son una cita simple ASCII (
"
), pero son unos Unicode / UTF-8 serie -0xE2
,0x80
,0x9C
, oU+201C
- que el terminal no manejará como se podría esperar.La sugerencia de Kiwy de
cat -A
también hace el trabajo:Nota: cuando se usa
echo "..." | hd
, existe la posibilidad de que bash sustituya partes de la cadena que está tratando de inspeccionar. Esto es particularmente preocupante cuando se intenta inspeccionar los componentes de un script.Por ejemplo, intente:
Estos métodos están reemplazando componentes con el texto relevante. Para evitar esto, utilice uno de los siguientes enfoques. Tenga en cuenta el uso de comillas simples (
'
) y un " heredoc citado " ("EOF"
).fuente
echo "[ -f /etc/openvpn.ovpn ]" | hd
devoluciones[...] c2 a0 [...]
. Podemos ver el espacio ininterrumpido del personaje c2 a0 UT-8Puede usar
cat
con la-A
opción: del manual:Entonces
cat -A yourscrip.sh
te mostrará personajes invisibles y extraños.fuente
echo "[ -f /etc/openvpn.ovpn ]" | cat -A
devoluciones[ -f /etc/openvpn/client.ovpnM-BM- ]$
. Podemos ver el espacio ininterrumpido del personaje M-BM- UT-8echo "<your command>" | hd
Deberia trabajar. Busque retroceso (0x08) o caracteres con códigos> = 80.echo "<your command>" | wc -b
y comprobar que el recuento coincide con lo que ves también es una buena idea.Copiar cosas de archivos producidos por cualquier cosa con "Office" en su nombre es peligroso, porque dicho software a menudo se toma la libertad de reemplazar caracteres: en francés, busque las comillas dobles reemplazadas por "guillemets", en inglés las comillas simples reemplazadas por sus abrir / cerrar equivalentes. El más difícil que encontré fue un espacio sin interrupciones de ancho 0 en el medio del nombre de un archivo (3 días de tiempo de inactividad del servidor ...).
fuente
hd
es breve,hexdump
que también se menciona en la respuesta de Attie.hd
es equivalente ahexdump -C
.echo "[ -f /etc/openvpn.ovpn ]" | hd
devoluciones[...] c2 a0 [...]
. Podemos ver el espacio sin interrupción del personaje c2 a0 UT-8Bash y otros shells como zsh pueden abrir la línea de comando actual en un editor. El acceso directo predeterminado para bash es
C-x C-e
( CtrlX CtrlE), y se abre en el primer disponible de$VISUAL
,$EDITOR
y emacs. En la práctica, esto es invaluable para depurar y modificar comandos complejos. Dependiendo de cómo lo mire, zsh es más amigable que bash aquí: cuando el editor sale, bash ejecuta el comando inmediatamente, mientras que zsh espera a que presione Enter(lo que le brinda más oportunidades de editar el comando).Después de abrir el comando en un editor, puede configurar sus editores para mostrar caracteres no ASCII de manera diferente.
Por ejemplo, con Vim , usando esta configuración:
O, adaptando los métodos de otras respuestas:
fuente