メモリ

メモリ

内部にバッシュリファレンスマニュアルそれは次のように言います:

lithist 有効にしてcmdhistこのオプションを有効にすると、複数行コマンドは、可能であればセミコロン区切り文字を使用するのではなく、埋め込み行を使用して履歴に保存されます。

だから私の質問は次のようになりますどこで/いつ/どのように可能ですか?

私のデバイスで機能を有効にしてテストしてみました。GNU bash, バージョン 4.4.12(1) - リリースこの方法:

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不可能ですか?私は何が間違っていましたか?

答え1

Aは歴史からaを得る正しい方法では\<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

実際の複数行コマンド:

複数行コマンドの可能な例は次のとおりです。

$ for a in one two
> do echo "test $a"
> done
test one
test two

次の場合、履歴は1行に縮小されますcmdhist is set

$ 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     

ある時点で、.clearを使用して(メモリから)履歴を消去したため、各コマンドの番号が変更されました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回試してください。

  • デフォルト値のcmdhist(設定)とlithist(未設定)を使用します。
  • 同時設定
  • どちらも設定されていません。
  • unset cmdhistでlithistを設定することは意味がありません(テストできます)。

実行するコマンドのリスト:

$ 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 つの複数行コマンドは次のように終了します。

  • 2行目の1つ(1行、1コマンド)。
  • 4行で示された複数行の1つ(複数行の1つのコマンド)
  • 6から8まで番号が付けられた複数行のうちの1つ

さて、さて、ファイルで何が起こっていますか?もう言ってたけど…

最後にファイルから:

簡単です。ファイルに書き込んで猫を送って確認してください。

$ 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つだけで、各行はコマンドで再度読み取られます。

解決策はありますか?はい、追加の区切り文字を使用します。
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

答え2

これは複数行のコマンドではないようです(あなたがリターンをエスケープしたため)。実際の報酬があることをするならば違いがあります。

$ 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

答え3

iTermは複数行のコマンドを完全に処理し、複数行のコマンドを1つのコマンドとして保存し、++を使用してCmd履歴を閲覧できます。より多くのiTermのヒントをご覧ください:Shift;iTermで効果的に作業する

答え4

私は努力した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 

関連情報