自動バックアップ

自動バックアップ

時々私のzsh録音が切り捨てられたことを発見し(または完全に失われているかもしれません)、バックアップから復元する必要があります。

たとえば、今日は次のようになります。

ls -lh ~/.zsh_history
-rw-------  1 stripe  staff    32K 21 Feb 10:20 /Users/stripe/.zsh_history

しかし、数日前のバックアップでは次のようになります。

-rw-------@  1 stripe  staff  203K 17 Feb 22:36 /Volumes/Time Machine Backups/.../Users/stripe/.zsh_history

zsh多くの履歴を保存するように設定したので、シェルが意図的にファイルを切り捨てるのに問題はありません。

unsetopt share_history
setopt inc_append_history
setopt hist_ignore_all_dups
HISTSIZE=500000
SAVEHIST=$HISTSIZE

他の人がこれを経験し、それを軽減する方法を見つけましたか?zsh私が知らない春の大掃除機能はありますか?

答え1

ZTE

さまざまな理由で、履歴ファイルが切り捨て、失われた、または消去される可能性があります。その理由は次のとおりです。

  • zsh履歴ファイルの破損(シェルを開くときの停電/システムエラーのため、この場合はシステムエラー時に実行するようにfsckを設定する必要があります)
  • Zsh設定ファイルがロードされていません(たとえば、$HOMEenv変数が定義されていない場合など)
  • サポートしていない歴史記録保管所の人zsh リセット履歴を作成できます
  • 漂白剤などのクリーニングツール
  • Zsh構成エラー
  • シェル間の共有には$HISTFILEより厳しい制限があります$HISTSIZE。たとえば、$HISTFILEbashrcなしでzshでbashシェルを実行すると、サブシェルはzshから継承された変数を使用し、$HISTSIZEbashrc変数に定義された変数を適用します。
  • など。

ノート

過去に使用可能な設定オプション

HISTFILE="$HOME/.zsh_history"
HISTSIZE=500000
SAVEHIST=500000
setopt BANG_HIST                 # Treat the '!' character specially during expansion.
setopt EXTENDED_HISTORY          # Write the history file in the ":start:elapsed;command" format.
setopt INC_APPEND_HISTORY        # Write to the history file immediately, not when the shell exits.
setopt SHARE_HISTORY             # Share history between all sessions.
setopt HIST_EXPIRE_DUPS_FIRST    # Expire duplicate entries first when trimming history.
setopt HIST_IGNORE_DUPS          # Don't record an entry that was just recorded again.
setopt HIST_IGNORE_ALL_DUPS      # Delete old recorded entry if new entry is a duplicate.
setopt HIST_FIND_NO_DUPS         # Do not display a line previously found.
setopt HIST_IGNORE_SPACE         # Don't record an entry starting with a space.
setopt HIST_SAVE_NO_DUPS         # Don't write duplicate entries in the history file.
setopt HIST_REDUCE_BLANKS        # Remove superfluous blanks before recording entry.
setopt HIST_VERIFY               # Don't execute immediately upon history expansion.
setopt HIST_BEEP                 # Beep when accessing nonexistent history.

回答

~/.zshrcこの場合は、次の設定を使用することをお勧めします(ファイルに設定)。

HISTFILE=/specify/a/fixed/and/different/location/.history
HISTSIZE=500000
SAVEHIST=500000
setopt appendhistory
setopt INC_APPEND_HISTORY  
setopt SHARE_HISTORY

選ぶ

小さなスクリプトを使用して履歴ファイルのサイズを確認し、必要に応じてバックアップから復元できます(から~/.zshrc)。

if [ /home/my/zsh/hist/file -lt 64000 ]; then
    echo "History file is lower than 64 kbytes, restoring backup..."
    cp -f /mybackup/histfile /home/my/zsh/hist/file
fi

リンク

追加情報は以下で確認できます。これそしてこれ質問。

答え2

私はそうは思わないどのzshオプションは貴重です.zsh_history

私は.zsh_history何年もランダムに切り捨てられましたが、まだ理由がわかりません。 StackExchangeで見つけることができるすべてのオプションを試しましたが、明らかにoh-my-zshで設定を試みました。

自動バックアップ

次に、私の記録が切れるのを気にしないように、次の行を追加しましたcrontab -e

30 14 * * * cp /home/my_user/.zsh_history /backup/folder/zsh_history_$(date +\%Y_\%m_\%d).bak

anacron他のツールやrsync他のツールを自由に使用してください。目的は、文書を安全な場所に収集することです.zsh_history。そのうち少なくとも一部には必須情報が含まれています。

履歴の復元

回復が必要なとき一つ潜在的に切り捨てられたバックアップを完了するには、.zsh_history次のコマンドを使用できます。

cat zsh_history*.bak | awk -v date="WILL_NOT_APPEAR$(date +"%s")" '{if (sub(/\\$/,date)) printf "%s", $0; else print $0}' | LC_ALL=C sort -u | awk -v date="WILL_NOT_APPEAR$(date +"%s")" '{gsub('date',"\\\n"); print $0}' > .merged_zsh_history

みんなこの素晴らしいところから来ました。Article("zsh 記録ファイルの結合")

履歴ファイルをマージし、コマンドを並べ替え、重複エントリを削除し、複数行のコマンドを中断しません。

数週間後

予定通り、私のコンテンツは.zsh_history明確な理由なくブロックされました。

私のバックアップは正常に動作します。それらのいくつかはまだ同じファイルに重複したコマンドを持っています。上記のawkコードは、ファイル間の正確な重複(時間+持続時間+コマンド)のみを識別しますが、たとえばls別の時間に呼び出された場合はそれを保持します。だから私は次のような小さなRubyスクリプトを書いた。

#! /usr/bin/env ruby
# Ruby script to merge zsh histories. In case of duplicates, it removes the old timestamps.
# It should do fine with multi-line commands.
# Make backups of your backups before running this script!
#
# ./merge_zsh_histories.rb zsh_history_*.bak ~/.zsh_history > merged_zsh_history

MULTILINE_COMMAND = "TO_BE_REMOVED_#{Time.now.to_i}"

commands = Hash.new([0,0])

ARGV.sort.each do |hist|
  $stderr.puts "Parsing '#{hist}'"
  content = File.read(hist)
  content.scrub!("#")
  content.gsub!(/\\\n(?!:\s*\d{10,})/, MULTILINE_COMMAND)
  should_be_empty = content.each_line.grep_v(/^:/) + content.each_line.grep(/(?<!^): \d{10,}/)
  raise "Problem with those lines : #{should_be_empty}" unless should_be_empty.empty?
  content.each_line do |line|
    description, command = line.split(';', 2)
    _, time, duration = description.split(':').map(&:to_i)
    old_time, _old_duration = commands[command]
    if time > old_time
      commands[command] = [time, duration]
    end
  end
end

commands.sort_by{|_, time_duration| time_duration}.each{|command, (time, duration)|
  puts ':%11d:%d;%s' % [time, duration, command.gsub(MULTILINE_COMMAND, "\\\n")]
}

それはうまく動作し、すべてのコマンドを含み、最大のバックアップよりも大きくない有効なzsh_historyファイルを返します。

答え3

代替ソリューションが見つかりました。カスタムコマンド履歴ツールをインストールしました。

私はそれを使用していますマクフライ。よりスマートな履歴検索のためのきちんとした機能に加えて、この場合の鍵は、ツールが機能するために独自の記録データベースを維持する必要があることです。

SQLiteデータベース内のコマンドの終了ステータス、タイムスタンプ、および実行ディレクトリを追跡するためのシェル履歴を強化します。

私の願いは、私のデータベースが.zsh_history壊れ続けていても、McFlyのsqliteデータベースがまだ私の後ろを守るということです。

実際、.zsh_historyMcFlyは互換性の理由で自動的に更新され、約1ヶ月半が経過した今までデータが失われたことを見たことはありません。 sqliteと.zsh_historyファイルの両方が着実に増加しています。私は.zsh_history今370Kに達しましたが、これは新しい記録だと思います。

答え4

回答いただくと遅れません。私のzhistoryファイルが破損した場合、常に突然のシャットダウンが原因で発生します。再起動時に ~/.zhistory ファイルを編集し、目立つように壊れた行を削除しました。通常は最後の行ですが、時には最後の行から2番目までです。それから私は大丈夫でしょう。私のzhistoryファイルはほぼ1megで、長年にわたっています。

関連情報