bashコマンド文字列の逐語的な文字を確認するにはどうすればよいですか?


15

今朝、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
  • 最初のコマンドは、geditで編集されたスクリプトから貼り付けられました。
  • 2番目は、ターミナルで直接入力されました。

掘り下げた後、30番目の文字(client.confと "]"の間のスペース)を削除し、スペースに置き換えるとコマンドが再び機能することがわかりました。

私の仮定は正しかった:未知の空白文字がコマンド滑り込んだが、問題は:

  1. コマンドをデバッグできるように、端末でこれらの文字を表示するにはどうすればよいですか?さらに重要なこと:
  2. これが再び発生するのを防ぐにはどうすればよいですか?

ところで、Ubuntu 18.04 /フランス語を実行しています。コマンドを貼り付けるスクリプトはUSBドライブにあり、Windowsでも編集されている可能性があります。


非常に良い答えをありがとう。不良文字は、c2 a0の改行なしスペースUTF-8文字です。sedで特別な「M-BM-」キャラクターを削除する方法の質問には、そのキャラクターに関する興味深い事実があります。

奇妙なことは、スクリプトにこのキャラクターがないことです。だから、どこから来たのか分からない。


3
そのような文字を強調表示するエディターを使用します。構文の強調表示も非常に役立ちます。Webからターミナルに直接貼り付けないで、常に前述のエディターを使用してください。
チョロバ

2
Yoは、履歴リストで問題のコマンドを見つけて、16進表示プログラムを介して出力をパイプしたい場合があります。長いリストを探し回る必要がないように、コマンドを再実行して履歴リストの一番下に配置して実行するかhistory 2|xxdhistoryコマンド自体が常にリストの最後であるため)、またはを入力しhistory|grep "CommandWithProblem"|xxdます。の代わりに他の16進表示プログラムを使用できますxxdが、これは私の好みの形式にデフォルト設定されます。
AFH

@Gabriel Glenn、答えが役立ったそれぞれにコメントするのではなく、ティックを使用して、最高/最も役立つ/どんな答えでも「受け入れられた」とマークしてください。情報
Attie

1
で提案されているように@Attieは、はい、私は、私は通常、最良の答えを受け入れる前に24時間待機します:meta.stackexchange.com/questions/5234/...
ガブリエル・グレン・

1
個人的に私は使用しますset -x。これにより、コマンドと分割方法が表示されます。「ここの悪いキャラクター」とは必ずしも言えませんが、bashがそのキャラクターで分裂していないことを示します。
パトリック

回答:


11

1つのオプションは、16進ビューアーまたはエディターで使用しようとしている文字を調べることです。hexdump端末に限定されている場合は、適切なオプションです。

$ 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

あなたがここにいることを見ることができるspaceclose-square-bracespace正しいです- 、0x20、。0x5D0x20

これらの値はASCIIコードで、16進数で表示されます。範囲外の値が0x20- 0x7Eではない印字可能な文字 ASCIIが懸念され、最も可能性の高いコマンドラインインタフェースとうまく再生されません限り。

注:私はあなたの最初の「コピー壊れにおける使用のための」行hexdumpに何かを交換しているので、上記の例をない--ASCIIスペースを元のソースとあなたのレンダリングされた質問間のASCIIスペースで。


これを繰り返すには、次の手順を実行します。

  1. 入力hexdump -Cv <<"EOF"して押すEnter
  2. 使用したいテキストを貼り付けます
  3. EOF独自の行を入力して、押しますEnter

あなたが発見したように、ターミナルとコマンドラインインターフェースは特殊文字をうまく処理しません。文書の書式設定にあまり注意を払っていない場合、Microsoft Smart Word(およびその他)で「スマートクォート」やemダッシュを使用すると問題が発生します。リストは続きます...

違いを見つける:(上部は「スマート引用符」、下部は「直線引用符」です)

スマートクオートとストレートクオートの例

$ 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

ここでは、開いている引用符は、(単純なASCII引用符ではありません")が、ユニコード/あるUTF-8シリーズ- 、0xE20x800x9CまたはU+201Cご想像のとおり、端末が扱えないであろう- 。

Kiwyの提案cat -Aも仕事をします。

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

注:を使用echo "..." | hdすると、検査しようとしている文字列の一部をbashが置き換える可能性があります。これは、スクリプトのコンポーネントを検査しようとする場合に特に懸念されます。

例:

$ echo "${USER}"
attie

$ echo "`whoami`"
attie

$ echo "$(whoami)"
attie

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

これらのメソッドは、コンポーネントを関連するテキストに置き換えています。これを回避するには、次のいずれかの方法を使用します。単一引用符(')と引用されたヒアドック"EOF")の使用に注意してください。

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

$ echo '`whoami`'
`whoami`

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

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

この解決策は機能しecho "[ -f /etc/openvpn.ovpn ]" | hd ます[...] c2 a0 [...]c2 a0 UT-8の文字の改行なしスペース
ガブリエルグレン

18

あなたは使うことができcat-Aオプション:マニュアルから:

   -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

そのcat -A yourscrip.shため、目に見えない奇妙なキャラクターが表示されます。


7
この解決策は機能しecho "[ -f /etc/openvpn.ovpn ]" | cat -Aます[ -f /etc/openvpn/client.ovpnM-BM- ]$M-BM-が見えます UT-8キャラクターのノンブレークスペース
ガブリエルグレン

@GabrielGlennはこれがあなたを助けてくれてうれしいです。
-Kiwy

9

echo "<your command>" | hd動作するはずです。バックスペース(0x08)または80以上のコードの文字を探します。echo "<your command>" | wc -bまた、カウントが表示と一致することを確認することもお勧めします。

そのようなソフトウェアはしばしば文字を置き換えるために自由を必要とするため、そのようなソフトウェアはしばしば自由に文字を置き換えるため、ファイルからものをコピーすることは危険です。同等のオープン/クローズ。私がこれまでに見つけた最も困難なものは、ファイル名の真ん中にある幅0の改行なしスペース(3日間のサーバーダウンタイム...)でした。


2
言及する価値hdがあるのは短く、hexdumpそのことはAttieの回答でも言及されています。
ミカエルケアー

@MikaelKjær-Ubuntuでは、hdと同等hexdump -Cです。
AFH

1
@xenoid:私は「Windowsで編集した」と言ったが、Office Writerで編集したわけではない。編集された場合は、Notepad ++を使用していました。
ガブリエルグレン

1
この解決策は機能しecho "[ -f /etc/openvpn.ovpn ]" | hd ます[...] c2 a0 [...]c2 a0 UT-8文字の改行なしスペース
ガブリエルグレン

2

Bash、およびzshのような他のシェルは、エディターで現在のコマンドラインを開くことができます。bashのデフォルトのショートカットはC-x C-eCtrlX CtrlE)であり、最初に利用可能な$VISUAL$EDITORおよびemacs で開きます 。実際には、これは複雑なコマンドのデバッグと変更に非常に役立ちます。見方によっては、zshはここでのbashよりも使いやすいです。エディターが終了すると、bashはすぐにコマンドを実行しますが、zsh Enterはユーザーが押すのを待機します(コマンドを編集する機会が増えます)。

エディターでコマンドを開いた後、非ASCII文字を異なる方法で表示するようにエディターを構成できます。

たとえば、Vimでは、次の設定を使用します。

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

ここに画像の説明を入力してください

または、他の回答の方法を調整します。

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$
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.