AWK: 他のレコードのフィールドの結合

AWK: 他のレコードのフィールドの結合

一方file:

2018-03-22 foo/bar/baz
2020-09-30 Lorem/ipsum/dolor
2021-10-01 yadda/yadda/yadda
2022-03-14 blah/blah/blah

(実際のファイルにはこのような数千行が含まれています)

文字列を取得する方法2018-03-22_2022-03-14?これは、レコード1のフィールド1、下線、最後のレコードのフィールド1を連結したものです。

私はこれを思い出しました:

$ awk 'BEGIN{ORS="_"}NR==1{print $1} END{print $1}' file | sed 's/_$//'
2018-03-22_2022-03-14

働くが複雑ではないawksedパイプやサブシェルだけを使用したり使用したりすることなく、同じ結果を得る方法です。実際にそのような方法がありますか?

答え1

専用バージョンsed:

sed 's/ .*//;1h;$!d;H;g;y/\n/_/' file
  • s/ .*//スペースの後ろのすべての項目を削除し、日付のみを保持するために使用されます。
  • 1h1空白に行の日付をコピーhold
  • $!d d最後の行を除くすべての行を削除
  • ここに到着すると、最後の行にあるため、H最初の日付を含むこの行を前のスペースに追加してから、両方をパターンスペースにコピーします。g
  • 今残っている唯一のことは、挿入された改行(追加のため)を下線に置き換えることです。y/\n/_/

(あなたは少し短いです)

答え2

移植性のためにこのセクションで実装print $1(または使用$anything)しないでくださいEND。これは、このセクションの対応するエントリが$0POSIX に従って定義されていない動作であるためです。一部のawksでは、この部分が最後の行から読み取られた最初のフィールドの値になり、他の場合はnullになり、他の場合は別の値になることがあります。$1END$1END

すべてのUnixシステムのすべてのシェルでawkを使用してください。

$ awk -v OFS='_' 'NR==1{beg=$1} {end=$1} END{print beg, end}' file
2018-03-22_2022-03-14

_または、入力ファイルが空の場合は、単一のファイルを印刷しないでください。

awk -v OFS='_' 'NR==1{beg=$1} {end=$1} END{ if (NR) print beg, end}' file

上記は、入力に行が1つしかない場合、その行間$1で同じ値が繰り返されることを前提としています_。これが望ましくない場合は、質問を更新してこのケースの要件を明確にしてください。

答え3

出力制御の場合printf

$ awk 'NR==1{printf("%s_", $1)}END{print $1}' f
2018-03-22_2022-03-14

答え4

大容量ファイルの処理に時間がかかるため、大容量入力ファイルを使用することをお勧めしますheadtailawksed

$ cat input.txt
2018-03-22 foo/bar/baz
2020-09-30 Lorem/ipsum/dolor
2021-10-01 yadda/yadda/yadda
2022-03-14 blah/blah/blah
{ head -n1 input.txt && tail -n1 input.txt; } |
  cut -d ' ' -f1 | paste -sd _ -
2018-03-22_2022-03-14

関連情報