상태:csv 파일에는 다양한 날짜 형식의 날짜 열이 있으며 이를 명시적인 날짜 형식(예: +"%m-%d-%Y")으로 변환하고 싶습니다.
파일 데이터 예:파일 이름 = Date_Test_new.csv
3/29/2019, Test, "I am new to, Unix", 04-05-2023
03/29/19, Test, "I am new to, Unix", 04-5-2023
Apr-29-2019, Test, "I am new to, Unix", "Apr-01-2019"
3/29/2019, Test, "I am new to, Unix", "Apr-01-2019"
**Source Date formats**
DD-MMM-YY -> 08-Sep-23
DD-MMM-YYYY -> 08-Sep-2023
MM/DD/YY -> 09/08/23
MM/DD/YYYY -> 09/08/2023
MM-DD-YYYY -> 09-08-2023
YYYYMMDD -> 20230908
DDMMMYY -> 08Sep23
원하는 출력
03-29-2019,Test, "I am new to, Unix", 04-05-2023
03-29-2019, Test, "I am new to, Unix", 04-05-2023
04-29-2019, Test, "I am new to, Unix", 04-01-2019
03-29-2019, Test, "I am new to, Unix", 04-01-2019
시도했지만 구문 오류가 발생합니다.
awk -F ',' '$1="date -d "$1" +"%m-%d-%Y" " ' Date_Test_new.csv > New_Output.csv
즉, 파일에 있는 전체 날짜 형식 열을 다른 날짜 형식으로 변환하려면 어떻게 해야 합니까?
어떤 도움이라도 나에게는 훌륭한 학습 경험이 될 것입니다. 감사해요
답변1
실제 데이터가 유효한 CSV 형식, 즉 필드로 구분된 쉼표 뒤에 공백이 없다고 가정하고 GNU awk를 사용 하고 3rg arg를 사용하여 다음을 수행 FPAT
합니다 .gensub()
match()
$ cat tst.awk
BEGIN {
split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",tmp)
for (i in tmp) {
mths[tmp[i]] = i
}
FPAT = "[^,]*|(\"([^\"]|\"\")*\")"
OFS = ","
}
{
for ( i=1; i<=NF; i++ ) {
val = gensub(/^"|"$/,"","g",$i)
day = mth = yr = 0
if ( match(val,/^([0-9]{1,2})-([[:alpha:]]{3})-([0-9]{2}|[0-9]{4})$/,d) ) {
# D-MMM-YY or DD-MMM-YY or ...YYYY
day = d[1]
mth = mths[d[2]]
yr = d[3]
}
else if ( match(val,/^([[:alpha:]]{3})-([0-9]{1,2})-([0-9]{2}|[0-9]{4})$/,d) ) {
# MMM-D-YY or MMM-DD-YY or ...YYYY
day = d[2]
mth = mths[d[1]]
yr = d[3]
}
else if ( match(val,/^([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{2}|[0-9]{4})$/,d) ) {
# M/D/YY or M/DD/YY or MM/D/YY or MM/DD/YY or ...YYYY
day = d[2]
mth = d[1]
yr = d[3]
}
else if ( match(val,/^([0-9]{1,2})-([0-9]{1,2})-([0-9]{2}|[0-9]{4})$/,d) ) {
# M-D-YY or M-DD-YY or MM-D-YY or MM-DD-YY or ...YYYY
day = d[2]
mth = d[1]
yr = d[3]
}
else if ( match(val,/^([0-9]{2})([[:alpha:]]{3})([0-9]{2})$/,d) ) {
# DDMMMYY
day = d[1]
mth = mths[d[2]]
yr = d[1]
}
else if ( match(val,/^([0-9]{4})([0-9]{2})([0-9]{2})$/,d) ) {
# YYYYMMDD
day = d[3]
mth = d[2]
yr = d[1]
}
if ( length(yr) == 2 ) {
yr = "20" yr
}
day += 0
mth += 0
yr += 0
if ( (1 <= day) && (day <= 31) &&
(1 <= mth) && (mth <= 12) &&
(1 <= yr) && (yr <= 9999) ) {
$i = sprintf("%04d-%02d-%02d", yr, mth, day)
}
}
print
}
$ awk -f tst.awk Date_Test_new.csv
2019-03-29,Test,"I am new to, Unix",2023-04-05
2019-03-29,Test,"I am new to, Unix",2023-04-05
2019-04-29,Test,"I am new to, Unix",2019-04-01
2019-03-29,Test,"I am new to, Unix",2019-04-01
귀하가 나열한 모든 날짜 형식 등을 다루었지만 else if ( match(...) ) { ... }
구문 분석할 수 있는 다른 형식에 대한 블록을 추가하기만 하면 됩니다.
match()
일부 정규식을 완화하여 좀 더 유사한 호출을 병합하거나 더 잘 작동하는 경우 일부 정규식을 더 엄격하게 만들 수도 있습니다.
sprintf()
원하는 출력 형식으로 변경하세요 . 하지만 계속 사용하는 것이 좋습니다.ISO 8601 날짜 형식, YYYY-MM-DD
, 나는 이 날짜의 후속 처리를 용이하게 하기 위해 이것을 사용합니다.
원하는 경우 수표의 유효 날짜를 자유롭게 추가하거나 변경할 수 있습니다. 우리는 GNU awk를 사용하고 있으므로 원할 경우 각 블록의 입력 형식을 기억한 다음 하단에서 mktime()
새로 생성된 날짜를 에포크 이후의 초로 변환한 다음 strftime()
해당 초를 다시 원래 형식으로 변환하여 확인할 수 있습니다. 원래 날짜와 동일한 경우 정확한 일치 및 변환이 이루어지고 있는지 확실하게 확인하세요. 연습으로 남겨두세요... :-).
필드 구분 후 데이터에 공백이 있는 경우 ,
:
$ cat file
3/29/2019, Test, "I am new to, Unix", 04-05-2023
03/29/19, Test, "I am new to, Unix", 04-5-2023
Apr-29-2019, Test, "I am new to, Unix", "Apr-01-2019"
3/29/2019, Test, "I am new to, Unix", "Apr-01-2019"
다음을 사용하여 유효한 CSV로 변환할 수 있습니다.
$ awk 'BEGIN{FS=OFS="\""} {for (i=1; i<=NF; i+=2) gsub(/, /,",",$i)} 1' file
3/29/2019,Test,"I am new to, Unix",04-05-2023
03/29/19,Test,"I am new to, Unix",04-5-2023
Apr-29-2019,Test,"I am new to, Unix","Apr-01-2019"
3/29/2019,Test,"I am new to, Unix","Apr-01-2019"
위의 모든 내용은 필드에 개행 문자가 포함될 수 없다고 가정합니다. 필드에 줄 바꿈이 포함되어 있으면 더 많은 작업이 필요합니다. awk를 사용하여 CSV를 처리하는 방법에 대한 자세한 내용은 다음을 참조하세요.awk를 사용하여 csv를 효율적으로 구문 분석하는 가장 강력한 방법은 무엇입니까.