Bash script / awk để nhập và xuất tệp CSV

Sep 28 2020

Tôi đang gặp sự cố khi tạo tập lệnh bash / awk / sed sẽ lấy tệp CSV được phân tách bằng dấu phẩy gồm ba cột (tên, họ, ngày sinh) và xuất ra một tệp CSV khác có cùng các cột từ đầu vào bằng một cột bổ sung hiển thị sự khác biệt giữa ngày hiện tại và ngày sinh trong năm.

$ yourscript <input CSV file> <output CSV file>

input.csv có thể trông giống như sau:

bob,wag,06/13/1958
ashley,hay,01/23/1983
evan,bert,09/11/1972

output.csv sẽ giống như sau:

bob,wag,06/13/1958,62
ashley,hay,01/23/1983,37
evan,bert,09/11/1972,48

Trả lời

3 Cbhihe Sep 28 2020 at 14:46
$ cat data
bob,wag,06/13/1958
ashley,hay,01/23/1983
evan,bert,09/11/1972

Để xuất ra một tệp có tên output-filevà hiển thị thành STDOUT cùng lúc:

$ awk -v year=$(\date +%Y) 'BEGIN{FS="/"} {print $0 "," year-$3}' data | tee output-file
bob,wag,06/13/1958,62
ashley,hay,01/23/1983,37
evan,bert,09/11/1972,48

Hoặc chỉ xuất ra cùng một tệp:

$ awk -v year=$(\date +%Y) 'BEGIN{FS="/"} {print $0 "," year-$3}' data > output-file
2 Cbhihe Sep 30 2020 at 18:04

Để thực hiện các phép tính thời gian chính xác hơn, bạn có thể sử dụng gawkcác hàm thời gian và chuỗi (theo gợi ý của @ AdminBee). Sử dụng dữ liệu đầu vào như:

$ cat data
bob,wag,06/13/1958
ashley,hay,01/23/1983
evan,bert,09/11/1972

Bạn có thể nhận được chênh lệch thời gian tính theo ngày từ bây giờ đến ngày được hiển thị trên mỗi dòng, với:

$ awk -F, 'BEGIN{today=systime()} 
           {print $0 "," int((today-mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00))/(3600*24))}' \
           data | tee output-file

 bob,wag,06/13/1958,22755
 ashley,hay,01/23/1983,13765
 evan,bert,09/11/1972,17551

Đoạn mã:

int((today-mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00))/(3600*24))

thực hiện ba điều cơ bản cho mỗi dòng của tệp đầu vào:

  • nó tính toán thời gian đã trôi qua (tính bằng giây) kể từ 1970-01-01 00:00:00 UTC (trên hệ thống POSIX), không tính giây nhuận, với mktime(substr($3,7,4)" "substr($3,1,2)" "substr($3,4,2)" "00" "00" "00)
  • nó tính toán chênh lệch thời gian giữa đại lượng trên và biến today, chứa số giây đã trôi qua tại thời điểm thực hiện kể từ 1970-01-01 00:00:00 UTC.
  • nó chia chênh lệch thời gian theo giây cho 3600 * 24 để lấy số ngày bằng nhau và chỉ xem xét phần nguyên của kết quả, để lấy nguyên ngày int().

Bạn có thể chơi với nó để nhận chênh lệch thời gian tính theo giây, phút, giờ theo nhu cầu của bạn. HTH

MaheshK. Sep 28 2020 at 11:49

Để có được sự khác biệt về ngày tháng, bạn có thể sử dụng hàm bash nhỏ này

Sử dụng các số sau cho nhu cầu của bạn

  • # Để nhận chênh lệch ngày : 86400
  • # Để nhận Chênh lệch theo năm : 31536000

Hàm Bash

datediff() {
  current_date=$(date -d "$1" +%s)
  birth_date=$(date -d "$2" +%s)
  echo $(( (current_date - birth_date) / 31536000)) Years
}

Sử dụng:

datediff '9/28/2020' '1/1/1999'

Đầu ra:

 21 years
MarcinŚlusarz Jan 09 2021 at 09:58

Tùy thuộc vào những gì bạn thực sự muốn:

chênh lệch năm:

(echo "firstname,lastname,d"; cat input.csv) | csv-sqlite \
 "select *, strftime('%Y', 'now') - substr(d, 7, 4) as year_diff
  from input" | csv-header --remove

tuổi tác:

(echo "firstname,lastname,d"; cat input.csv) | csv-sqlite
  "select *, strftime('%Y', 'now') - substr(d, 7, 4) -
             case when strftime('%m%d', 'now') >= (substr(d, 1, 2) || substr(d, 4, 2))
             then 0 else 1 end as age
  from input" | csv-header --remove

csv-sqlite và csv-header là từ csv-nix-tools