May*_*ayD 5 shell-script text-processing date
设想:
我正在将文件中的日期值提取到变量中,默认情况下它采用 DD-MM-YYYY 格式。我必须从系统日期中减去这个日期。如果我的两个日期都采用 DD-MM-YYYY 格式,则减法会给出不正确的结果。所以我在谷歌上读了一点,决定将两个日期都格式化为 YYYY-MM-DD,因为这将在减法后给出正确的值。我已经在 YYYY-MM-DD 中成功格式化了系统日期,但是很难将从文件中获得的日期转换为 YYYY-MM-DD 格式。
以下解决方案适用于个位数日期:
$ date -d $(sed "s/-/\//g" <<< '9-2-1832') +%Y-%m-%d
Output : 1832-09-02
Run Code Online (Sandbox Code Playgroud)
但是当我尝试将日期转换为两位数时,如下所示:
$ date -d $(sed "s/-/\//g" <<< '19-07-2021') +%Y-%m-%d
Run Code Online (Sandbox Code Playgroud)
我得到输出
Invalid date '19/07/2021'
Run Code Online (Sandbox Code Playgroud)
在哪里:
19 - is Date of a month
07 - is Month i.e. July in this case.
2021 - is Year
Run Code Online (Sandbox Code Playgroud)
所需的输出为 -> 2021-07-19
我正在使用日期版本为 RH Linux:date (GNU coreutils) 8.22
请帮助提供上述问题的解决方案。
Sté*_*las 11
您可以切换到date允许指定输入格式的busybox :
$ date=19-7-2021
$ busybox date -D %d-%m-%Y -d "$date" +%F
2021-07-19
Run Code Online (Sandbox Code Playgroud)
(请注意019-007-2021,例如它不会接受日期)。
与 ast-open 实现相同date(不太可能在您的 RedHat 系统上开箱即用):
$ date -p %d-%m-%Y -d "$date" +%F
2021-07-19
Run Code Online (Sandbox Code Playgroud)
如果您使用的是 BSD 而不是 GNU 系统,您会这样做:
$ date -jf %d-%m-%Y -- "$date" +%F
2021-07-19
Run Code Online (Sandbox Code Playgroud)
或者您可以切换到zsh而不是bash原样具有内置的日期解析和格式设置:
$ zmodload zsh/datetime
$ strftime -rs t %d-%m-%Y $date && strftime %F $t
2021-07-19
Run Code Online (Sandbox Code Playgroud)
(strftime作为内置程序,可以访问标准strftime()和strptime()(带有-r)API)。
它还具有适当的拆分运算符和 aprintf可以以任意顺序接受参数(使用%n$...在大多数printf()实现中找到的语法,包括 GNU printf(),但不是printf内置bash的 GNUprintf独立实用程序),并且它不会将带有前导零的数字视为默认八进制:
$ printf '%3$04d-%2$02d-%1$01d\n' ${(s[-])date}
2021-07-19
Run Code Online (Sandbox Code Playgroud)
或者使用匿名函数:
$ (){ printf '%04d-%02d-%02d\n' $3 $2 $1; } ${(s[-])date}
2021-07-19
Run Code Online (Sandbox Code Playgroud)
或者在这里,数组反转运算符:
$ printf '%04d-%02d-%02d\n' ${(s[-]Oa)date}
2021-07-19
Run Code Online (Sandbox Code Playgroud)
Adm*_*Bee 10
在你的情况下,awk可能是一个更好的方法:
$ awk -F'-' '{printf("%04d-%02d-%02d\n",$3,$2,$1)}' <<< '19-07-2021'
2021-07-19
Run Code Online (Sandbox Code Playgroud)
如果格式硬编码为DD-YY-YYYY,还可以对整个表达式进行硬编码,并使用子串提取重新格式化,非常快:
#!/bin/bash
dmy=$(date +%d-%m-%Y)
ymd="${dmy: -4}-${dmy:3:2}-${dmy:0:2}"
echo "$dmy -> $ymd"
Run Code Online (Sandbox Code Playgroud)
如果格式是D[D]-M[M]-YYYY你可以使用正则表达式来重新格式化,这有点慢:
#!/bin/bash
dmy="9-2-1932"
if [[ "$dmy" =~ ^([[:digit:]]+)-([[:digit:]]+)-([[:digit:]]+)$ ]] ; then
ymd="${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-${BASH_REMATCH[1]}"
fi
echo "$dmy -> $ymd"
Run Code Online (Sandbox Code Playgroud)
您可以使用以下格式更好地格式化printf:
dmy="9-02-2032"
if [[ "$dmy" =~ ^([[:digit:]]+)-([[:digit:]]+)-([[:digit:]]+)$ ]] ; then
printf -v ymd '%.4d-%.2d-%.2d' \
"${BASH_REMATCH[3]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[1]}"
fi
echo "$dmy -> $ymd"
Run Code Online (Sandbox Code Playgroud)
这个答案的前一个版本证明我没有完全阅读它,转换YYYY-MM-DD为DD-MM-YYYY:
#!/bin/bash
ymd=$(date +%Y-%m-%d)
dmy="${ymd: -2}-${ymd:5:2}-${ymd:0:4}"
echo "$ymd -> $dmy"
Run Code Online (Sandbox Code Playgroud)
感谢大家参与各种解决方案。我相信很少有建议的解决方案对我有用,因为我将它们与我昨天发布此问题后自行解决该问题所使用的方法相关联。
我曾经IFS实现过它。
IFS=- read d m y <<<'19-7-2021'
printf '%.4d-%.2d-%.2d\n' "${y#0}" "${m#0}" "${d#0}"
Run Code Online (Sandbox Code Playgroud)
这将输出2021-07-19.
etc.会从 的值中${m#0}删除首字母,以防原始月份恰好是或,否则会被解释为无效的八进制数。0$m0809