web-dev-qa-db-ja.com

変数を介してbashスクリプトでdateコマンドを操作する方法

特定の日付のファイルがあり、UTC形式に変換したいと思います。だから私は小さなスクリプトを用意しました

以下のエラーが発生します:

date: option requires an argument -- 'd'
Try `date --help' for more information.
date: extra operand `16:16:53'

私のファイルの内容は次のようになります。

20191014161653042nmd
20191014161653052egc
20191004081901490egc
20191004081901493nex
20191004081901497nex
20191004081902531nex
20191004081902534ksd

私のコードは次のようになります:

for i in $(cut -f1 Firstfile)
do
echo "$i" > tmpfile
TIME=$(awk '{print substr($1,1,14)}' tmpfile | sed -re 's/^([0-9]{8})([0-9]{2})([0-9]{2})([0-9]{2})$/\1\\ \2:\3:\4/' | xargs date +@%s -d | xargs date -u +"%Y-%m-%dT%H:%M:%S" -d)
MSec=$(awk '{print substr($1,15,3)}' tmpfile)
Msg=$(awk '{print substr($1,18,3)}' tmpfile)
echo -e "$TIME.$MSec $Msg" >> ResultFile
done

コマンドを個別に使用すると、正常に機能し、目的の結果が得られます。

awk '{print substr($1,1,14)}' tmpfile | sed -re 's/^([0-9]{8})([0-9]{2})([0-9]{2})([0-9]{2})$/\1\\ \2:\3:\4/' | xargs date +@%s -d | xargs date -u +"%Y-%m-%dT%H:%M:%S" -d

スクリプトでこれを行っている間違いは何ですか? forループのスクリプトに渡すと機能しないのはなぜですか?

期待される結果:

2019-10-14T20:16:52.042 nmd
2019-10-14T20:16:52.052 egc
2019-10-04T12:19:01.490 egc

等々

1
Paul

問題は、dateを使用してxargsに渡すデータが多すぎることです。また、出力の一部にするために、最後に余分なテキスト文字列を渡さないでください。

操作全体をawkスクリプトで実行することをお勧めします。 GNU awkmawkの両方に、基本的なタイムスタンプ操作を行うための関数があります。

{
        YYYY    = substr($1, 1, 4)   # year
        mm      = substr($1, 5, 2)   # month
        dd      = substr($1, 7, 2)   # day
        HH      = substr($1, 9, 2)   # hour
        MM      = substr($1, 11, 2)  # minute
        SS      = substr($1, 13, 2)  # seconds
        sss     = substr($1, 15, 3)  # fractional seconds

        text    = substr($1, 18)     # the rest

        tm = mktime(sprintf("%s %s %s %s %s %s", YYYY, mm, dd, HH, MM, SS))
        printf("%s.%s %s\n", strftime("%Y-%m-%dT%H:%M:%S", tm, 1), sss, text)
}

これは、substr()を使用して、入力タイムスタンプのさまざまなコンポーネントをさまざまな変数に選択します。次に、Unix時間はmktime()を使用して計算され(入力時間はローカルタイムゾーンにあると想定されます)、これはstrftime()を使用して適切な形式の(UTC)タイムスタンプ文字列に変換されます。

分数秒(コードではsss)は時間計算の一部ではなく、入力から出力にそのまま転送されることに注意してください。

それを実行する:

$ awk -f script.awk file
2019-10-14T14:16:53.042 nmd
2019-10-14T14:16:53.052 egc
2019-10-04T06:19:01.490 egc
2019-10-04T06:19:01.493 nex
2019-10-04T06:19:01.497 nex
2019-10-04T06:19:02.531 nex
2019-10-04T06:19:02.534 ksd

awkマニュアルのmktime()およびstrftime()のドキュメントを参照してください。

2
Kusalananda

これはsedとbashを使用したバージョンです

 sed -re 's/^([0-9]{8})([0-9]{2})([0-9]{2})([0-9]{2})(([0-9]{3,}){0,1})([a-z].*)$/D="\1\ \2:\3:\4";M="\5";E="\7"/' /tmp/tmpfile  |\ 
  xargs -d'\n' -I=:= bash -c  '(=:=;echo $(date -u +"%Y-%m-%dT%H:%M:%S.$M" -d "TZ=\"America/New_York\" $D" )  $E)'

awk + sedを回避するためにsedステップを1つだけ実行しました
sedの2番目の部分のすべての\を削除しました

xargsの-Iオプションを使用して、find{}のように、argを使用する場所を指定します

日付の2回の使用を避けるために、日付の-dオプションでTZオプションを使用します

ここでは、入力のタイムゾーンとしてAmerica/New_Yorkを使用していますが、正しい値に変更する必要があります。

0
EchoMike444