人が読める日付に変換する必要がある新起源の日付を含むファイルがあります。私はすでに、次のように日付変換を実行する方法を知っています。
[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
sed
GNUは次の機能を実行できます。
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>; reboot
extraが使用されても、$
この行は置き換えられません。別の方法は次のとおりです。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 -f
OSXes 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
私の言語はアラビア語です:)