ファイルのエポックタイムスタンプを別の形式に置き換えるにはどうすればよいですか?

ファイルのエポックタイムスタンプを別の形式に置き換えるにはどうすればよいですか?

人が読める日付に変換する必要がある新起源の日付を含むファイルがあります。私はすでに、次のように日付変換を実行する方法を知っています。

[server01 ~]$ date -d@1472200700
Fri 26 Aug 09:38:20 BST 2016

sed.. しかし、ファイルを繰り返してすべての項目を変換する方法を見つけるのが難しいです。ファイル形式は次のとおりです。

#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web

答え1

sedGNUは次の機能を実行できます。

sed -E 's/^#([0-9]+).*$/date -d @\1/e'

これは非常に非効率的です(そして任意の命令注入の脆弱性が発生しやすい1 。これは、実際には、次のように各行dateに対してシェルとコマンドを実行することを意味するためです。#xxxxシェルwhile readループほど悪い。ここでは、日付変換機能が組み込まれているテキスト処理ユーティリティ、perlまたはなどを使用することをお勧めします。gawk

perl  -MPOSIX -pe 's/^#(\d+).*/ctime $1/se'

または:

gawk '/^#/{$0 = strftime("%c", substr($0, 2))};1'

1^#([0-9]).*(この回答の以前のバージョンで行ったように)代わりに作成すると、^#([0-9]).*$UTF-8ロケール(現在の標準)などのマルチバイトロケールで入力が似ています。#1472047795<0x80>;rebootここでは<0x80>、セクション値0x80という単語はそうではありません。s最終的に実行されるコマンドなどの有効な文字形式です。date -d@1472047795<0x80>; rebootextraが使用されても、$この行は置き換えられません。別の方法は次のとおりです。s/^#([0-9])/date -d @\1 #/eつまり、日付以降の部分を#xxxシェルコメントとして保持することです。

答え2

ファイル形式が一貫していると仮定すると、bashファイルを1行ずつ読み込み、指定された形式であることをテストしてから変換できます。

while IFS= read -r i; do [[ $i =~ ^#([0-9]{10})$ ]] && \
      date -d@"${BASH_REMATCH[1]}"; done <file.txt

BASH_REMATCH最初の要素が正規表現一致で最初にキャプチャされたグループである配列です(=~この場合はepoch)。


ファイル構造を維持するには、次のようにします。

while IFS= read -r i; do if [[ $i =~ ^#([0-9]{10})$ ]]; then printf '#%s\n' \
   "$(date -d@"${BASH_REMATCH[1]}")"; else printf '%s\n' "$i"; fi; done <file.txt

これにより、変更された内容がSTDOUTに出力され、ファイルに保存されますout.txt。たとえば、次のようになります。

while ...; do ...; done >out.txt

これで、必要に応じて元のファイルを置き換えることができます。

mv out.txt file.txt

例:

$ cat file.txt
#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web

$ while IFS= read -r i; do [[ $i =~ ^#([0-9]{10})$ ]] && date -d@"${BASH_REMATCH[1]}"; done <file.txt
Wed Aug 24 20:09:55 BDT 2016
Wed Aug 24 20:11:46 BDT 2016
Wed Aug 24 20:13:58 BDT 2016

$ while IFS= read -r i; do if [[ $i =~ ^#([0-9]{10})$ ]]; then printf '#%s\n' "$(date -d@"${BASH_REMATCH[1]}")"; else printf '%s\n' "$i"; fi; done <file.txt
#Wed Aug 24 20:09:55 BDT 2016
ll /data/holding/email
#Wed Aug 24 20:11:46 BDT 2016
cat /etc/rsyslog.conf
#Wed Aug 24 20:13:58 BDT 2016
ll /data/holding/web

答え3

他のすべての回答は、date変換する必要がある各起源の日付に対して新しいプロセスを作成します。入力が大きいと、パフォーマンスオーバーヘッドが追加される可能性があります。

ただし、GNU日付には、-f単一のプロセスインスタンスが新しいdateフォークなしで入力日を継続的に読み取ることができる便利なオプションがあります。したがって、私たちは使用することができ、sed入力pasteがどんなに大きくても、date各入力は一度だけ生成されます(2xの場合)。sed

$ paste -d '\n' <( sed '2~2d;y/#/@/' epoch.txt | date -f - ) <( sed '1~2d' epoch.txt )
Wed Aug 24 07:09:55 PDT 2016
ll /data/holding/email
Wed Aug 24 07:11:46 PDT 2016
cat /etc/rsyslog.conf
Wed Aug 24 07:13:58 PDT 2016
ll /data/holding/web
$ 
  • これら2つのsedコマンドは、デフォルトで入力の偶数行と奇数行をそれぞれ削除し、正しいエポックタイムスタンプ形式を提供するために#最初のコマンドも置き換えられます。@
  • その後、最初の出力は必要な日付変換を実行して受け取る各入力行sedにパイプされます。date -f
  • その後、これら2つのストリームは目的の単一出力にインターリーブされますpaste。構成<( )Bashプロセスの交換これは、Pasteが与えられたファイル名から読み取ると思うように効果的に騙されます。実際には、内部コマンドからパイプされた出力を読み取っています。奇数と偶数の出力ラインを改行文字で区切るように指示-d '\n'します。pasteたとえば、タイムスタンプを他のテキストと同じ行に表示する場合は、この設定を変更(または削除)できます。

このコマンドには複数のGNUismとBashismがあります。これはPosixと互換性がなく、GNU / Linuxの世界外に移植可能であると期待してはいけません。たとえば、date -fOSXes BSDバリアントで別の操作を実行しますdate

答え4

sedを使用してください:

sed -r 's/\#([0-9]*)/echo $(date -d @\1)/eg' test.txt

出力:

ر أغس 24 16:09:55 EET 2016
ll /data/holding/email
ر أغس 24 16:11:46 EET 2016
cat /etc/rsyslog.conf
ر أغس 24 16:13:58 EET 2016
ll /data/holding/web

私の言語はアラビア語です:)

関連情報