bashリファレンスマニュアル には次のように記載されています。
lithist
有効で、cmdhist
オプションが有効になっている場合、複数行のコマンドは、可能な場合はセミコロン区切り文字を使用するのではなく、改行が埋め込まれた履歴に保存されます。
これで私の質問:どこで/いつ/どのようにこれが可能ですか?
GNU bash、バージョン4.4.12(1)-releaseでこの機能を有効にしてテストしようとしました:
shopts -s cmdhist
shopts -s lithist
echo -n "this is a test for a ";\
echo "multiline command"
それから私は
history | tail
これに似た出力を期待しています:
101 shopts -s cmdlist
102 shopts -s lithist
103 echo -n "this is a test for a ";\
echo "multiline command"
104 history
まだ代わりにこれを入手してください:
101 shopts -s cmdlist
102 shopts -s lithist
103 echo -n "this is a test for a "; echo "multiline command"
104 history
明らかなように、複数行コマンド(bash履歴番号103のコマンド)は、 "セミコロン区切り文字を使用するよりも改行を埋め込んだ"で保存されていません。ここでlithist
が不可能だったのはなぜですか?私は何を間違えましたか?
\<new line>
は、履歴で<new line>
を取得する正しい方法ではありません。
履歴行はシェルメモリ(ディスクではない)に保持されているため、履歴行のみを処理します。
あなたがしたように、いくつかのコマンドを入力しましょう:
$ echo -n "this is a test for a ";\
> echo "two line command"
書き込んだ行として何がメモリに保存されましたか?
$ history 2
514 echo -n "this is a test for a ";echo "two line command"
515 history 2
ご覧のとおり、バックスラッシュの後に改行が続く「行の継続」が削除されました。
必要に応じて(man bashから):
\ペアが表示され、円記号自体が引用符で囲まれていない場合、\は行継続として扱われます(つまり、入力ストリームから削除され、事実上無視されます)。
引用すると改行が入る可能性があります。
$ echo " A test of
> a new line"
A test of
a new line
そして、この時点で、歴史はそれを反映します:
$ history 2
518 echo "A test of
a new line"
519 history 2
複数行コマンドの考えられる例の1つは、次のとおりです。
$ for a in one two
> do echo "test $a"
> done
test one
test two
cmdhist is set
の場合、これは1つの履歴行に折りたたまれます。
$ shopt -p cmdhist lithist
shopt -s cmdhist
shopt -u lithist
$ history 3
24 for a in one two; do echo "test $a"; done
25 shopt -p cmdhist lithist
26 history 3
ある時点で(メモリ内の)履歴をhistory -c
でクリアしたため、各コマンドの番号が変更されました。
Cmdhistの設定を解除すると、次のようになります。
$ shopt -u cmdhist
$ for a in one two
> do echo "test $a"
> done
test one
test two
$ history 5
5 shopt -u cmdhist
6 for a in one two
7 do echo "test $a"
8 done
9 history 5
各行(完全なコマンドではありません)は、履歴内の別々の行にあります。
lithist
が設定されている場合でも:
$ shopt -s lithist
$ for a in one two
> do echo "test $a"
> done
test one
test two
$ history 5
12 shopt -s lithist
13 for a in one two
14 do echo "test $a"
15 done
16 history 5
ただし、両方が設定されている場合:
$ shopt -s cmdhist lithist
$ for a in one two
> do echo "test $a"
> done
$ history 5
23 history 15
24 shopt -p cmdhist lithist
25 shopt -s cmdhist lithist
26 for a in one two
do echo "test $a"
done
27 history 5
for
コマンドは、セミコロン(;
)の代わりに「改行」を使用した複数行コマンドとして保存されました。 lithistが設定されていない上記と比較してください。
上記のすべては、シェルのメモリに保持されているコマンドのリストを使用して説明されました。コマンドはディスクに書き込まれませんでした。 (デフォルト)ファイル~/.bash_history
は変更されていません。
そのファイルは、実行中のシェルが終了すると変更されます。その時点で、履歴はファイルを上書きするか(histappend
が設定されていない場合)、そうでない場合は追加されます。
コマンドをディスクにコミットする場合は、 これを設定してください :
export Prompt_COMMAND='history -a'
これにより、各コマンドラインが新しい各コマンドラインのファイルに追加されます。
それでは、cmdhistとlithistとのビジネスに取り掛かりましょう。見た目ほど単純ではありません。しかし、心配しないでください。すべてがすぐに明らかになります。
以下のすべてのコマンドを入力するのに時間がかかるとしましょう(ショートカット、エイリアス、関数はありません。実際のコマンドが必要です。申し訳ありません)。
最初にメモリ(history -c
)とディスク(バックアップ)(history -w
)そして3回試す:
実行するコマンドのリスト:
$ history -c ; history -w # Clear all history ( Please backup).
$ shopt -s cmdhist; shopt -u lithist
$ for a in one two
> do echo "test $a"
> done
$ shopt -s cmdhist; shopt -s lithist
$ for a in one two
> do echo "test $a"
> done
$ shopt -u cmdhist; shopt -u lithist
$ for a in one two
> do echo "test $a"
> done
あなたはこれで終わります(メモリ内):
$ history
1 shopt -s cmdhist; shopt -u lithist
2 for a in one two; do echo "test $a"; done
3 shopt -s cmdhist; shopt -s lithist
4 for a in one two
do echo "test $a"
done
5 shopt -u cmdhist; shopt -u lithist
6 for a in one two
7 do echo "test $a"
8 done
9 history
3つの複数行コマンドは次のように終了します。
わかりました、しかしファイルで何が起こりますか?すでに言ってください..。
簡単です。ファイルに書き込んで、これを確認してください。
$ history -w ; cat "$HISTFILE"
shopt -s cmdhist; shopt -u lithist
for a in one two; do echo "test $a"; done
shopt -s cmdhist; shopt -s lithist
for a in one two
do echo "test $a"
done
shopt -u cmdhist; shopt -u lithist
for a in one two
do echo "test $a"
done
history
history -w ; cat "$HISTFILE"
行番号はなく、コマンドのみです。複数行がどこから始まりどこで終わるかを知る方法はありません。複数行があっても見分ける方法はありません。
実際、それがまさに起こることです。コマンドが上記のようにファイルに書き込まれた場合、ファイルが読み戻されると、複数行に関する情報が失われます。
区切り文字(改行)は1つだけで、各行は1つのコマンドとして読み戻されます。
これに対する解決策はありますか、はい、追加の区切り文字を使用します。
HISTTIMEFORMATのようなものがそれを行います。
この変数が何らかの値に設定されている場合、各コマンドが実行された時刻は、コメント(#
)文字の後のエポックからの秒数(はい、常に秒)としてファイルに保存されます。
変数を設定して~/.bash_history
ファイルを書き直すと、次のようになります。
$ HISTTIMEFORMAT='%F'
$ history -w ; cat "$HISTFILE"
#1490321397
shopt -s cmdhist; shopt -u lithist
#1490321397
for a in one two; do echo "test $a"; done
#1490321406
shopt -s cmdhist; shopt -s lithist
#1490321406
for a in one two
do echo "test $a"
done
#1490321418
shopt -u cmdhist; shopt -u lithist
#1490321418
for a in one two
#1490321418
do echo "test $a"
#1490321420
done
#1490321429
history
#1490321439
history -w ; cat "$HISTFILE"
#1490321530
HISTTIMEFORMAT='%FT%T '
#1490321571
history -w ; cat "$HISTFILE"
これで、どこでどの行が複数行であるかがわかります。
形式'%FT%T '
は時間を示しますが、historyコマンドを使用する場合のみです。
$ history
1 2017-03-23T22:09:57 shopt -s cmdhist; shopt -u lithist
2 2017-03-23T22:09:57 for a in one two; do echo "test $a"; done
3 2017-03-23T22:10:06 shopt -s cmdhist; shopt -s lithist
4 2017-03-23T22:10:06 for a in one two
do echo "test $a"
done
5 2017-03-23T22:10:18 shopt -u cmdhist; shopt -u lithist
6 2017-03-23T22:10:18 for a in one two
7 2017-03-23T22:10:18 do echo "test $a"
8 2017-03-23T22:10:20 done
9 2017-03-23T22:10:29 history
10 2017-03-23T22:10:39 history -w ; cat "$HISTFILE"
11 2017-03-23T22:12:10 HISTTIMEFORMAT='%F'
12 2017-03-23T22:12:51 history -w ; cat "$HISTFILE"
13 2017-03-23T22:15:30 history
14 2017-03-23T22:16:29 HISTTIMEFORMAT='%FT%T'
15 2017-03-23T22:16:31 history
16 2017-03-23T22:16:35 HISTTIMEFORMAT='%FT%T '
17 2017-03-23T22:16:37 history
これは複数行のコマンドではないようです(リターンをエスケープしたため)。あなたが本当のリターンでそれをするならば、違いがあります。
$ for i in /tmp/g*
> do echo $i
> done
/tmp/gigabyte
$ shopt -s lithist
$ for i in /tmp/g*
> do echo $i
> done
/tmp/gigabyte
$ history
[...]
517 for i in /tmp/g* ; do echo $i ; done
518 shopt -s lithist
519 for i in /tmp/g*
do echo $i
done
520 history
shopt -s lithist cmdhist
を試しました。
ただし、ログアウトしてログインした後も、~/.bash_history
からの履歴の回復は複数行に分割されていました。
1953 2019-05-23 16:57:53 shopt -s cmdhist; shopt -s lithist
1954 2019-05-23 16:57:58 for i in 1 2 3
1955 2019-05-23 16:58:34 do echo $i
1956 2019-05-23 16:58:34 done
1957 2019-05-23 16:58:08 history 5
1958 2019-05-23 16:58:27 history -a
1959 2019-05-23 16:54:12 history 10 | less
この動作は予想されますか?
以下は~/.bash_history
の私の内容です:
#1558601873
shopt -s cmdhist; shopt -s lithist
#1558601878
for i in 1 2 3
do echo $i
done
#1558601888
history 5
#1558601907
history -a
#1558601652
history 10 | less
古い〜/ .bash_historyを削除してこの問題を解決すると、複数行の履歴が正常に機能します。ログアウトしてログインした後でも。
1 2019-06-12 13:53:11 \rm .bash_history
2 2019-06-12 13:53:27 fx mcd
3 2019-06-12 13:53:28 mcd ()
{
mkdir $@;
cd $1
}
4 2019-06-12 14:55:14 nmcli-restart-hotspot -s
5 2019-06-12 21:34:35 ssh lab
6 2019-06-12 23:38:45 history | less
iTermは複数行のコマンドを完全に処理し、複数行のコマンドを1つのコマンドとして保存してから、次のコマンドを使用できます。 Cmd+Shift+; 履歴をナビゲートします。 iTermを効果的に使用する でiTermのヒントをさらに確認してください。
継続行(行末の\
)は、何があっても削除されているようです。継続を行うには2つの代替方法があることに気づきました。
バッククォート。コマンド置換。 私は後者よりもこれを好む
$ echo "1st line";`
> `echo "2nd line"
1st line
2nd line
$ history 2
507 echo "1st line";`
`echo "2nd line"
508 history 2
ドル記号。まだコマンド置換を悪用しています。
$ echo "1st line";$(
> ) echo "2nd line"
1st line
2nd line
$ history 2
501 echo "1st line";$(
) echo "2nd line"
502 history 2
ええあまりない魅力的。考えてみれば、EOLのスラッシュがきれいだと思ったのはいつですか?
当初は:
を含めることを考えていましたが、表示されているように、置換はそれなしで機能するので、それを使用します。
すばらしいのは、shopt -u lithist
でも機能することです。 ~/.bash_history
から履歴をロードする新しいbashセッションを開始しても、それらは切断されます。