Bash 스크립트를 통해 CSV 파일의 날짜 변경

Bash 스크립트를 통해 CSV 파일의 날짜 변경

현재 다음과 같은 기록이 포함된 파일이 있습니다.

D20211011,S0519,306668,1
D20211004,S1600,306668,1
D20211009,S1604,306668,1
D20211010,S1605,306668,1
D20211006,S1610,306668,1
D20211011,S1611,306668,1

현재 날짜가 이라고 가정하면 20211011날짜가 현재 날짜보다 작은 행에만 변환을 적용해야 하며 과거 날짜가 있는 행은 현재 날짜로 업데이트해야 합니다.

위에 공유된 예에서는 2행에서 5행으로 변환이 수행되어야 합니다.

D20211004,S1600,306668,1 -> D20211011,S1600,306668,1
D20211009,S1604,306668,1 -> D20211011,S1604,306668,1
D20211010,S1605,306668,1 -> D20211011,S1605,306668,1
D20211006,S1610,306668,1 -> D20211011,S1610,306668,1

답변1

귀하의 경우 날짜가 ISO 스타일로 제공된다는 이점이 있습니다. 즉, 날짜를 정수 값으로 해석하고 산술 연산자( 및 )를 사용하여 간단하게 비교할 수 <있으면서도 올바른 순서를 생성할 수 있습니다 =.>

따라서 다음 awk프로그램을 사용할 수 있습니다.

awk -v cur="20211011" 'BEGIN{FS=OFS=","} {ldate=substr($1,2); if (ldate<cur) $1="D" cur} 1' input.csv

현재 날짜는 awk변수 로 정의됩니다 cur. 처음에는 입력 및 출력에 대한 필드 구분 기호가 로 설정됩니다 ,. 그런 다음 각 행에 대해 행 날짜는 해당 행의 필드 1에서 첫 번째 문자를 제거하여 결정됩니다. 결과 "정수"가 보다 작으면 cur및 의 내용을 연결하여 필드를 덮어씁니다. 규칙 블록 외부의 "흩어진" 콘텐츠로 보이는 것은 가능한 수정 사항을 포함하여 현재 줄을 인쇄하도록 지시합니다.Dcur1awk

답변2

노력하다 awk:

awk -v today=$(date +%Y%m%d) '
    BEGIN{FS=OFS=","}
    substr($1,2)<today{$1="D"today;}
1' file
  • -v today=$(date +%Y%m%d)현재 날짜를 포함하는 변수를 설정합니다.
  • BEGIN{FS=OFS=","}입력( FS) 및 출력( OFS) 필드 구분자를 설정합니다.
  • substr($1,2)<today첫 번째 필드를 잘라내어 D현재 날짜와 비교합니다.
  • $1="D"today;첫 번째 필드를 현재 날짜로 바꿉니다.
  • 1항상 true로 평가하여 라인을 인쇄합니다.

답변3

$ awk -v d='D20211011' 'BEGIN{FS=OFS=","} $1<d{$1=d} 1' file
D20211011,S0519,306668,1
D20211004,S1600,306668,1
D20211009,S1604,306668,1
D20211010,S1605,306668,1
D20211006,S1610,306668,1
D20211011,S1611,306668,1

$ awk -v d="$(date +'D%Y%m%d')" 'BEGIN{FS=OFS=","} $1<d{$1=d} 1' file
D20211012,S0519,306668,1
D20211012,S1600,306668,1
D20211012,S1604,306668,1
D20211012,S1605,306668,1
D20211012,S1610,306668,1
D20211012,S1611,306668,1

답변4

Raku(이전 Perl_6) 사용

raku -pe 's/ ^^ D <(\d*?)> \, /20211011/;'

@StéphaneChazelas가 OP에 대한 의견에서 지적했듯이 "미래 날짜"가 첫 번째 열에 나타날지는 확실하지 않습니다. 그렇지 않은 경우 s///위의 Raku 코드가 수행하는 간단한 교체로 충분합니다(숫자 비교에 관계없이 찾은 모든 날짜 숫자 교체 < = >).

< = >그러나 첫 번째 열을 숫자 비교를 기반으로 한 값 으로 업데이트하려는 경우 s///연산자의 대체 부분에 Raku 삼항 연산자가 포함된 블록을 실행하는 다음 Raku 코드를 사용할 수 있습니다.

raku -pe 'my Int $d=20211011; s/ ^^ D (\d*?) \, /D{$0 < $d ?? $d !! $0},/;'

입력 예:

D20211011,S0519,306668,1
D20211004,S1600,306668,1
D20211009,S1604,306668,1
D20211010,S1605,306668,1
D20211006,S1610,306668,1
D20211011,S1611,306668,1

출력 예(위의 Raku 코드 예):

D20211011,S0519,306668,1
D20211011,S1600,306668,1
D20211011,S1604,306668,1
D20211011,S1605,306668,1
D20211011,S1610,306668,1
D20211011,S1611,306668,1

두 번째 Raku 코드 예에서는 정확성을 추가로 확인하기 위해 변수의 $d유형이 제한되어 있습니다 Int. @AdminBee가 지적했듯이 첫 번째 열에 < = >연산자와 비교하여 여전히 올바른 결과를 제공 할 수 있는 ISO 날짜가 포함되어 있다는 것은 행운입니다 .

위의 Raku 코드의 (간단한) 두 번째 줄과 관련하여 유효한 날짜를 확인하기 위한 캡처에 대한 확인이 없다는 점에 유의해야 합니다 $0(예: 13번째 달 또는 32일이 발생하지 않는지 확인). 불완전한 날짜(예: 월/일)를 제외하는 코드도 없습니다.글꼴 없음년도).

OTOH는 Raku의 내장 지원 DateDateTime개체를 사용하여 적절한 날짜 유효성 검사를 추가하는 것이 상대적으로 쉽습니다(추가 모듈이 필요하지 않음, 아래 예제 및 링크).

$ echo "2020-02-29" | raku -ne '.Date.raku.say'
Date.new(2020,2,29)

$ echo "2021-02-29" | raku -ne '.Date.raku.say'
Day out of range. Is: 29, should be in 1..28
  in block <unit> at -e line 1

https://docs.raku.org/언어/temporal#index-entry-Date_and_time_functions
https://raku.org

관련 정보