web-dev-qa-db-ja.com

ビッグバンをエコーする方法!

エディターで開くのではなく、ファイルの内容をecho 'してスクリプトを作成しようとしました

echo -e "#!/bin/bash \n /usr/bin/command args"  > .scripts/command

出力

bash:!/ bin/bash:イベントが見つかりません

この奇妙な動作を bang に分離しました。

$ echo !
!  

$ echo "!"
bash: !: event not found

$ echo \#!
#!

$ echo \#!/bin/bash
bash: !/bin/bash: event not found
  • なぜbangがこれを引き起こしているのですか?
  • Bashが参照するこれらの「イベント」とは何ですか?
  • この問題を回避して「#!/ bin/bash」を画面またはファイルに出力するにはどうすればよいですか?
59
Stefan

単一引用符を使用してみてください。

echo -e '#!/bin/bash \n /usr/bin/command args'  > .scripts/command

echo '#!'

echo '#!/bin/bash'

問題は、bashが!/ bin/bashの履歴を検索しているために発生しています。一重引用符を使用すると、この動作を回避できます。

62
Richm

リッチが言った のように、bashは 履歴の一致 を実行しようとしています。これを回避するもう1つの方法は、\

$ echo \#\!/bin/bash
#!/bin/bash

二重引用符の内側には注意してください、\は削除されません:

$ echo "\!"
\!
18
Michael Mrozek

!は履歴の置換を開始します(「イベント」はコマンド履歴の行です)。たとえば、!lslsを含む最後のコマンドラインに展開し、!?foofooを含む最後のコマンドラインに展開します。特定の単語を抽出することもできます(例:!!:1は前のコマンドの最初の単語を指します)。詳細はマニュアルをご覧ください。

この機能は、コマンドラインエディションがプリミティブだった時代の以前のコマンドをすばやく呼び出すために開発されました。最新のシェル(少なくともbashとzsh)とコピーアンドペーストでは、履歴の拡張は以前ほど便利ではありません。

histchars変数を設定することで、履歴置換をトリガーする文字を変更できます。ヒストリ置換をめったに使用しない場合は、たとえば、 histchars='¡^'¡の代わりに!が履歴の展開をトリガーするようにします。 set +o histexpandで機能を完全にオフにすることもできます。

特定のコマンドラインで履歴の展開を無効にするには、$histcharsの3番目の文字としてspaceを使用できます。

histchars='!^ '

その後、先頭にスペースを入れてコマンドを入力すると、履歴の展開は行われません。

bash-4.3$ echo "#!/bin/bash"
bash: !/bin/bash: event not found
bash-4.3$  echo "#!/bin/bash"
#!/bin/bash

ただし、ignorespaceにコマンドラインを履歴に記録しないように指示する方法として、$HISTCONTROLbashが含まれる場合は、先行スペースも使用されることに注意してください。

両方の機能を独立させたい場合は、$histcharsの3番目の文字として別​​の文字を選択する必要があります。コマンドの解釈方法に影響を与えないものが必要です。いくつかのオプション:

  • バックスラッシュ(\)の使用:\echo fooは機能しますが、エイリアスまたはキーワードが無効になるという副作用があります。
  • TAB:最初の位置に挿入するには、 Ctrl+VTab でも。
  • 2つのキーを入力してもかまわない場合は、通常は最初の位置に表示されない任意の文字(%@?、自分のキーを選択)を選択して、それの空のエイリアス:

    histchars='!^%'
    alias %=
    

    次に、その文字、スペース、コマンドを入力します。

    bash-4.3$ % echo !!
    !!
    

(ただし、履歴の置換が無効になっているコマンドを記録することはできません。また、$histcharsのデフォルトの3番目の文字は#であるため、コメントで履歴の拡張が行われません。変更し、プロンプトでコメントを入力する場合、!シーケンスがそこで展開される可能性があるという事実に注意する必要があります。

4

提案されたソリューションは、たとえば次の例では機能しません。

$ bash -c "echo 'hello World!'"
-bash: !'": event not found
$

この場合、8進数のASCIIコードを使用してbangを印刷できます。

$ bash -c "echo -e 'hello World\0041'"
hello World!
$
2
Atti

まだ言及されていない簡単な解決策は、変数を使用することです:

$ var='!'
$ echo -e "#${var}/bin/bash \n /usr/bin/command args"  > .scripts/command

bang!の印刷はnot文字列が引用符で囲まれていない、または単一引用符で囲まれている、またはC-String内にある場合の問題

$ echo hi\!pal 'hi!pal' $'hi!pal'
hi!pal 'hi!pal' $'hi!pal'

Histexpandが無効になっている場合も問題ではありません(shopt -ou histexpandまたはset +o histexpandまたは単にset +H。hisexpand文字を変更してbang!を印刷しやすくすることもできます。 。

しかし、ポータブルで最も簡単な解決策は、varを使用することです。

$ var='!'
$ echo "hi${var}pal"
hi!pal
0
Isaac