Eu tive esse comportamento estranho nesta manhã em um terminal do 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
- O primeiro comando foi colado a partir de um script editado com o gedit.
- O segundo foi digitado diretamente no terminal.
Após algumas pesquisas, descobri que remover o 30º caractere (o espaço entre client.conf e "]") e substituí-lo por um espaço fazia com que o comando funcionasse novamente.
Minha suposição estava certa: um caractere em branco desconhecido entrou no comando , mas a pergunta é:
- Como posso revelar esses caracteres no terminal para poder depurar o comando? E mais importante:
- Como impedir que isso aconteça novamente?
BTW, eu executando o Ubuntu 18.04 / idioma francês, o script do qual colo o comando está em uma unidade USB e também pode ter sido editado no Windows.
Obrigado por suas respostas muito boas. O caractere inválido é um caractere UTF-8 de espaço c2 a0 . A questão Como remover o caractere especial 'M-BM-' com o sed tem um fato interessante sobre esse caractere.
O estranho é que o script está livre desse personagem. Então eu não sei de onde veio.
fonte
history 2|xxd
(porque ohistory
próprio comando é sempre o último da lista) ou digitehistory|grep "CommandWithProblem"|xxd
. Você pode usar qualquer outro programa de exibição hexadecimal em vez dexxd
, mas o padrão é o formato que eu gosto.set -x
. Isso mostraria o comando e como ele é dividido. Não seria necessariamente dizer "personagem ruim aqui", mas mostraria que o bash não estava se dividindo nesse personagem.Respostas:
Uma opção é observar os caracteres que você está tentando usar com um visualizador ou editor hexadecimal.
hexdump
é uma boa opção se você estiver limitado ao terminal.Você pode ver aqui que o
space
,close-square-brace
,space
estão corretas -0x20
,0x5D
,0x20
.Esses valores são códigos ASCII, exibidos em hexadecimal . Qualquer valor fora do intervalo
0x20
-0x7E
não é um " caractere imprimível " no que diz respeito ao ASCII e provavelmente não funcionará bem com interfaces de linha de comando.Nota: Copiei sua primeira linha " quebrada " para uso no
hexdump
exemplo acima, portanto, algo substituiu o espaço não-ASCII por um espaço ASCII entre sua fonte original e sua pergunta renderizada.Para repetir isso, execute as seguintes etapas:
hexdump -Cv <<"EOF"
e pressioneEnterEOF
em uma linha própria e pressioneEnterTerminais e interfaces de linha de comando não lidam bem com caracteres especiais - como você descobriu. Se você não for muito cuidadoso com a formatação de documentos, também terá problemas com o Microsoft Word (e outros) usando " aspas inteligentes ", traços, a lista continua ...
Descubra a diferença: (a parte superior é " aspas inteligentes ", a parte inferior é " aspas diretas ")
Aqui, as aspas abertas não são uma citação ASCII simples (
"
), mas estão Unicode / UTF-8 séries -0xE2
,0x80
,0x9C
ouU+201C
- que o terminal não irá lidar com como você poderia esperar.A sugestão de Kiwy
cat -A
também faz o trabalho:Nota: ao usar
echo "..." | hd
, você tem a chance de que o bash substitua partes da string que você está tentando inspecionar. Isso é particularmente preocupante ao tentar inspecionar componentes de um script.Por exemplo, tente:
Esses métodos estão substituindo componentes pelo texto relevante. Para evitar isso, use uma das seguintes abordagens. Observe o uso de aspas simples (
'
) e um " heredoc citado " ("EOF"
).fonte
echo "[ -f /etc/openvpn.ovpn ]" | hd
retorna[...] c2 a0 [...]
. Podemos ver o c2 a0 UT-8 caracteres espaço não-quebraVocê pode usar
cat
com a-A
opção: no manual:Então
cat -A yourscrip.sh
, você mostrará personagens invisíveis e estranhos.fonte
echo "[ -f /etc/openvpn.ovpn ]" | cat -A
retorna[ -f /etc/openvpn/client.ovpnM-BM- ]$
. Podemos ver a M-BM UT-8 caracteres espaço não-quebraecho "<your command>" | hd
Deveria trabalhar. Procure backspace (0x08) ou caracteres com códigos> = 80.echo "<your command>" | wc -b
e verificar se a contagem corresponde ao que você vê também é uma boa ideia.Copiar coisas de arquivos produzidos por qualquer coisa com "Office" em seu nome é perigoso, porque esse software geralmente tem a liberdade de substituir caracteres: em francês, procure aspas duplas substituídas por "guillemets", em inglês para aspas simples substituídas por seus abrir / fechar equivalentes. O mais difícil que eu já encontrei foi um espaço sem quebra de largura 0 no meio de um nome de arquivo (3 dias de inatividade do servidor ...).
fonte
hd
é curtohexdump
e também é mencionado na resposta de Attie.hd
é equivalente ahexdump -C
.echo "[ -f /etc/openvpn.ovpn ]" | hd
retorna[...] c2 a0 [...]
. Podemos ver o c2 a0 UT-8 caracteres espaço não-quebraO Bash e outros shells, como o zsh, podem abrir a linha de comando atual em um editor. O atalho padrão para a festança é
C-x C-e
( CtrlX CtrlE), e abre no primeiro disponível de$VISUAL
,$EDITOR
e emacs. Na prática, isso é inestimável para depuração e modificação de comandos complexos. Dependendo de como você olha, o zsh é mais amigável do que o bash aqui: quando o editor sai, o bash executa o comando imediatamente, enquanto o zsh espera que você pressione Enter(dando mais chances de editar o comando).Depois de abrir o comando em um editor, você pode configurar seus editores para mostrar caracteres não ASCII de maneira diferente.
Por exemplo, com o Vim , use estas configurações:
Ou, adaptando os métodos das outras respostas:
fonte