日付条件についてはわかりません。

日付条件についてはわかりません。

その人が過去1年以内に生まれていない場合は、person.csv(下)から行を削除しようとします。

データセット1:

"Index","User Id","First Name","Last Name","Date of birth","Job Title"
"1","9E39Bfc4fdcc44e","new, Diamond","Dudley","06 Dec 1945","Photographer"
"3","32C079F2Bad7e6F","Ethan","Hanson","08 Mar 2014","Actuary"
"2","aaaaaaa, bbbbbb","Grace","Huerta","21 Jan 2023","Visual merchandiser"

したがって、予想される出力は次のようになります(最後の行は1年以内に削除されました)。

"Index","User Id","First Name","Last Name","Date of birth","Job Title"
"1","9E39Bfc4fdcc44e","new, Diamond","Dudley","06 Dec 1945","Photographer"
"3","32C079F2Bad7e6F","Ethan","Hanson","08 Mar 2014","Actuary"

私はawkを使って次のことをしようとしています。

awk -F , '{print $5 ....}' person.csv > output.csv

ただし、各日付行を(今日から1年を引いた値)と比較する方法はわかりません。

データセット2:時には二重引用符で囲まれたフィールドに二重引用符があります(例:line1 field4)。

"Index","User Id","First Name","Last Name","Date of birth","Job Title"
"1","9E39Bfc4fdcc44e","new, Diamond","Dudley (aka "dud")","03 Oct 2023","Photographer"
"3","32C079F2Bad7e6F","Ethan","Hanson","03 Dec 2022","Actuary"
"2","aaaaaaa, bbbbbb","Grace","Huerta","21 Jan 2023","Visual merchandiser"

「sed」がこれを行うことができれば、私もそれについて開いています。どんな助けでもお願いします。ありがとうございます!

答え1

仮定:

  • すべての列/フィールドは二重引用符で囲まれています。
  • 二重引用符はデータの一部として表示されません。それ以外の場合は、-F'"'フィールド区切り文字として基本文字以外の文字が必要です。
  • OP(オペレーティングシステム)はdateこの-dパラメータをサポートします(たとえば、16 Sep 2023OPシステムの「今日」date -d '-1 year' '+%Y%m%d'が生成される場合20220916
  • OPでは、締め切りは何でも可能であると述べたので(例:-1年、-7日など)、(オペレーティングシステム)を使用してdate特定の形式で期限を作成しますYYYYMMDD(そうでない場合は、コードを追加するする必要があります)awk。 「-1年」、「-7日」など様々な条件を処理できます。)

離れてawkいる:

cutoff=$(date -d '-1 year' '+%Y%m%d')                             # change '-1 year' to the desired condition;
                                                                  # alternatively: manually set to the desired date (in YYYYMMDD format)

awk -v cutoff="${cutoff}" -F'"' '                                 # set awk variable "cutoff" to the value of the OS variable of the same name
                                                                  # field delimiter is double quotes; this means data fields are even-numbered (eg, 5th field is the 10th "-delimited field)
BEGIN { mlist="JanFebMarAprMayJunJulAugSepOctNovDec" }
NR>1  { split($10,a,/[[:space:]]+/)                               # split 5th data field on spaces; a[1]=day a[2]=month a[3]=year
        m=sprintf("%02d", ( (index(mlist,a[2])+2) /3) )           # convert 3-letter month to 2-digit month
        if ( a[3] m a[1] > cutoff) next                           # if new date is greater than the cutoff then skip to the next line of input
      } 
1                                                                 # print the current line
' person.csv

これで以下が生成されます。

"Index","User Id","First Name","Last Name","Date of birth","Job Title"
"1","9E39Bfc4fdcc44e","new, Diamond","Dudley","06 Dec 1945","Photographer"
"3","32C079F2Bad7e6F","Ethan","Hanson","08 Mar 2014","Actuary"

パフォーマンスの観点...

この回答には単一のオペレーティングシステム呼び出しが必要で、date1つのファイル記述子を開く/閉じる必要があります(出力が別のファイルにリダイレクトされる場合は2つ)。

dateGillesの答えには、各入力行に対するオペレーティングシステムの呼び出しが必要です。そして各呼び出しに対してファイル記述子を開閉するのに費用がかかるオーバーヘッドですdate

テスト実行:

100K line file          # per comment from OP
GNU awk 5.1.0
GNU date 8.32
Ubuntu 20.04
i7-1260P

この答え:

real    0m0.198s        <<< 546 times faster
user    0m0.198s
sys     0m0.000s

ザイルズの答え:

real    1m48.229s       <<<
user    1m30.598s
sys     0m23.999s

両方の実行の出力はファイルに保存されます。diffaは、両方の出力ファイルに違いがないことを示しています(つまり、両方の答えは同じ結果セットを生成します)。


この場合、OPはすべてのフィールドが二重引用符で囲まれていることを示しています。

一部のフィールドを二重引用符で囲むことができない場合は、ペアへGNU awk's 'FPAT'の単一の呼び出しのみを使用して実行できますdate。たとえば、次のようになります。

cutoff=$(date -d '-1 year' '+%Y%m%d')

awk -v cutoff="${cutoff}" '
BEGIN { FPAT="([^,]+)|(\"[^\"]+\")"
        mlist="JanFebMarAprMayJunJulAugSepOctNovDec"
      }
NR>1  { f5=$5
        gsub(/"/,"",f5)                                           # strip double quotes from 5th data field
        split(f5,a,/[[:space:]]+/)                                # change from 10th field to 5th field
        m=sprintf("%02d", ( (index(mlist,a[2])+2) /3) )
        if ( a[3] m a[1] > cutoff) next
      }
    1
' person.csv

上記と同じテスト基準を使用して、この回答の実行時間は次のとおりです。

real    0m0.861s        <<<
user    0m0.850s
sys     0m0.009s

FPAT(代わりに-F'"')入力解析に基づくと、実行時間は約4倍になりますが、それでも108秒よりはるかに高速です。

答え2

GNUの使用そしてGNU1年の条件:

awk -v epoch1y=$(date -d '1 year ago' +%s) '
    BEGIN{FPAT="([^,]*)|(\"[^\"]+\")"}
    NR>1{
        cmd="date -d " $5 " +%s"
        epoch=( (cmd | getline line) > 0 ? line : "N/A")
        close(cmd)
        if (epoch > epoch1y) next
    }
    1
' person.csv

出力

"Index","User Id","First Name","Last Name","Date of birth","Job Title"
"1","9E39Bfc4fdcc44e","new, Diamond","Dudley","06 Dec 1945","Photographer"
"3","32C079F2Bad7e6F","Ethan","Hanson","08 Mar 2014","Actuary"

説明する

コードは明確で簡潔で読みやすくする必要があります。

明らかでない部分はFPAT特殊変数(内容別に分ける)、単に次のより多くのユースケースを処理できます-F,

ノート一部のプログラムは、二重引用符の間に新しい行を含むCSVデータをエクスポートします。 gawkはこの問題を解決する方法を提供しません。 CSVデータの公式仕様が存在しますが、まだやるべきことはありません。FPATメカニズムは、ほとんどの状況に対してエレガントなソリューションを提供します。、Gawk開発者はこれに満足しています。


これはシェル命令を実行し、後で変数を入力するためのgetlineヒントです。awkgetline


1最後にはを意味するので、特定のtrue条件trueではデフォルトでprint現在の行を意味します。


通貨に関する文書close():https://www.gnu.org/software/gawk/manual/html_node/Close-Files-And-Pipes.html


epochUnix タイムスタンプ: 後に経過した秒数1/1/1970

答え3

CSVの引用規則を理解していないため、awkこれを行うにはCSV認識ツールを使用することをお勧めします。

CSV処理ツールの使用csvkit:

$ csvsql -I --query "SELECT * FROM file WHERE \`Date of birth\` <= date('now', '-1 year')" file
Index,User Id,First Name,Last Name,Date of birth,Job Title
1,9E39Bfc4fdcc44e,"new, Diamond",Dudley,06 Dec 1945,Photographer
3,32C079F2Bad7e6F,Ethan,Hanson,08 Mar 2014,Actuary

これは、日付の解析と日付の計算をデータベースバックエンド(SQLite)に委任します。

出力は、参照する必要があるフィールドのみを参照します。引用したい場合みんなフィールドに結果をcsvformat -U1(他のcsvkitツール)に渡します。

編集:更新された質問で誤って参照されたフィールドは"Dudley (aka "dud")"csvkitツール(ここでは表示されません)によって変換されます。"Dudley (aka dud"")"""


csvkitツールなし、SQLiteのみを使用:CSVファイルとクエリから直接データをロードします。 SQLiteにはCSVをサポートするリーダーとライターが含まれているため、データが適切に参照されることを確認できます。

rm -f data.db
sqlite3 data.db \
    '.headers on' \
    '.mode csv' \
    '.import file mytable' \
    "SELECT * FROM mytable WHERE \`Date of birth\` <= date('now', '-1 year')"

私のシステム(ファンなしの「Intel(R)Core(TM)i5-4300U CPU @ 1.90GHz」)では、100,000レコードに約0.75秒かかり、そのうち0.3秒はSQLiteデータベースを構築するのにかかります。 1Mレコードの場合は7秒未満かかり、そのうち4秒はデータベースの構築にかかります。 10M行の場合、操作には約1分15秒かかり、そのうち45秒はデータベースの構築に使用されます。

編集:更新された質問で誤って参照されたフィールドは、"Dudley (aka "dud")"SQLite CSVリーダー/作成者によって正しく参照されたフィールド(ここでは表示されません)に変更されます。"Dudley (aka ""dud"")"

答え4

IFS=$'\n'
lyear_old_sec=$(date -d "1 year ago" +%s)
echo '"Index","User Id","First Name","Last Name","Date of birth","Job Title"'
for i in $(cat sup.txt|awk 'NR>1')
do
dat_de=$(echo $i | awk -F "," '{print $(NF-1)}'|sed 's/"//g')
date_de_second=$(date -d "$dat_de" +%s)
if [[ $date_de_second -lt $lyear_old_sec ]]
then
echo $i
fi
done

関連情報