2009-12-03 68 views
39

Làm cách nào để phân tích ngày trong bash, với các trường riêng biệt (năm, tháng, ngày, giờ, phút, giây) thành các biến khác nhau?Ngày phân tích cú pháp trong Bash

Định dạng ngày là: YYYY-MM-DD hh:mm:ss

Trả lời

52

Liệu nó phải bash? Bạn có thể sử dụng coreutils /bin/date nhị phân GNU đối với nhiều biến đổi:

$ date --date="2009-01-02 03:04:05" "+%d %B of %Y at %H:%M and %S seconds" 
02 January of 2009 at 03:04 and 05 seconds 

này phân tích các ngày nhất định và hiển thị nó trong định dạng lựa chọn. Bạn có thể điều chỉnh theo ý muốn theo nhu cầu của bạn.

+6

Đây có phải là phần mở rộng Linux không? Cả FreeBSD hoặc Mac OSX dường như không hỗ trợ nó. –

+1

Đây là ngày cũ GNU cũ: $ date --version ngày (GNU coreutils) 7.4 Bản quyền (C) 2009 Free Software Foundation, Inc. Giấy phép GPLv3 +: GNU GPL phiên bản 3 hoặc mới hơn . Đây là phần mềm miễn phí: bạn có thể tự do thay đổi và phân phối lại nó. KHÔNG CÓ BẢO HÀNH, trong phạm vi pháp luật cho phép. Được viết bởi David MacKenzie. –

+0

Tại sao 'date --date =" \ 'date \' "' không hoạt động? – Luc

6
$ t='2009-12-03 12:38:15' 
$ a=(`echo $t | sed -e 's/[:-]/ /g'`) 
$ echo ${a[*]} 
2009 12 03 12 38 15 
$ echo ${a[3]} 
12 
+2

không cần phải gọi lệnh bên ngoài – ghostdog74

0

bạn đã thử sử dụng cắt chưa? một cái gì đó như thế này: DAYOFWEEK = date|cut -d" " -f1

+0

Điều đó chỉ tách ngày và giờ chứ không phải từng phần riêng lẻ. –

2

tinh khiết Bash:

date="2009-12-03 15:35:11" 
saveIFS="$IFS" 
IFS="- :" 
date=($date) 
IFS="$saveIFS" 
for field in "${date[@]}" 
do 
    echo $field 
done 

2009 
12 
03 
15 
35 
11 
+0

Không cần sử dụng mảng ở đây. Chỉ cần 'set junk $ date; shift' thay vì 'date = ($ date)' và 'cho field' thay vì vòng lặp mảng. Đó sẽ là một phiên bản 'thuần túy sh', thậm chí còn tốt hơn! – Idelic

1

khác bash tinh khiết

$ d="2009-12-03 15:35:11" 
$ d=${d//[- :]/|} 
$ IFS="|" 
$ set -- $d 
$ echo $1 
2009 
$ echo $2 
12 
$ echo [email protected] 
2009 12 03 15 35 11 
3

Phương pháp mảng có lẽ là tốt hơn, nhưng đây là những gì bạn đã yêu cầu cụ thể đối với:

IFS=" :-" 
read year month day hour minute second < <(echo "YYYY-MM-DD hh:mm:ss") 
+1

Tôi thích điều này nhất. Một phím tắt, cũng không thay đổi vĩnh viễn IFS: 'IFS =": - "đã đọc YMYY-MM-DD hh: mm: ss" – ephemient

25

Điều này là đơn giản, chỉ cần chuyển đổi dấu gạch ngang và dấu hai chấm của bạn đến một không gian (không cần phải thay đổi IFS) và sử dụng 'đọc' trên cùng một dòng:

read Y M D h m s <<< ${date//[-:]/ } 

Ví dụ:

$ date=$(date +'%Y-%m-%d %H:%M:%S') 
$ read Y M D h m s <<< ${date//[-: ]/ } 
$ echo "Y=$Y, m=$m" 
Y=2009, m=57 
2

thay vì sử dụng vỏ kịch bản, kết hợp chặt chẽ trong kịch bản của bạn tự như dưới đây wheever bạn cần:

a=date +%Y 
b=date +%S 
c=date +%H 

một sẽ là năm b sẽ là giây c sẽ giờ. và vân vân.

2

Một giải pháp cho vấn đề của OP:

IFS=' -:' read y m d h m s<<<'2014-03-26 16:36:41' 

Chuyển đổi một ngày sang định dạng khác với BSD date và GNU date:

$ LC_ALL=C date -jf '%a %b %e %H:%M:%S %Z %Y' 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T 
2014-03-26 16:36:41 
$ gdate -d 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T 
2014-03-26 16:36:41 

GNU date nhận WedMar ngay cả trong phi Miền địa phương tiếng Anh nhưng BSD date thì không.

Chuyển đổi giây kể từ kỷ nguyên đến một ngày và thời gian với ngày tháng và BSD ngày GNU:

$ gdate -d @1234567890 '+%F %T' 
2009-02-14 01:31:30 
$ date -r 1234567890 '+%F %T' 
2009-02-14 01:31:30 

Chuyển đổi giây để giờ, phút và giây với một vỏ POSIX, POSIX awk, GNU date, và BSD date :

$ s=12345;printf '%02d:%02d:%02d\n' $((s/3600)) $((s%3600/60)) $((s%60)) 
05:25:45 
$ echo 12345|awk '{printf "%02d:%02d:%02d\n",$0/3600,$0%3600/60,$0%60}' 
05:25:45 
$ gdate -d @12345 +%T 
05:25:45 
$ date -r 12345 +%T 
05:25:45 

Chuyển đổi giây đến vài ngày, giờ, phút và giây:

$ t=12345678 
$ printf '%d:%02d:%02d:%02d\n' $((t/86400)) $((t/3600%24)) $((t/60%60)) $((t%60)) 
142:21:21:18 
2

Tôi có định dạng thời gian nhập khác nhau, do đó, đây là giải pháp linh hoạt hơn. Lệnh chuyển đổi ngày trong BSD/macOS là

date -jf in_format [+out_format] in_date 

nơi định dạng sử dụng strftime (xem man strftime).

Đối với định dạng đầu vào cho YYYY-MM-DD hh:mm:ss:

$ date -jf '%Y-%m-%d %H:%M:%S' '2017-05-10 13:40:01' 
Wed May 10 13:40:01 PDT 2017 

Để đọc chúng vào các biến riêng biệt, tôi lấy ý tưởng NVRAM, nhưng cho phép bạn sử dụng bất kỳ định dạng strftime:

$ date_in='2017-05-10 13:40:01' 

$ format='%Y-%m-%d %H:%M:%S' 

$ read y m d H M S <<< "$(date -jf "$format" '+%Y %m %d %H %M %S' "$date_in")" 

$ for var in y m d H M S; do echo "$var=${!var}"; done 
y=2017 
m=05 
d=10 
H=13 
M=40 
S=01 

Trong tôi trường hợp, tôi muốn chuyển đổi giữa các múi giờ (xem thư mục /usr/share/zoneinfo của bạn cho tên vùng):

$ format=%Y-%m-%dT%H:%M:%S%z 

$ TZ=UTC date -jf $format +$format 2017-05-10T02:40:01+0200 
2017-05-10T00:40:01+0000 

$ TZ=America/Los_Angeles date -jf $format +$format 2017-05-10T02:40:01+0200 
2017-05-09T17:40:01-0700 
Các vấn đề liên quan