我正在尝试修改文本中存在 as2016-Dec-24
或 的日期2016-12-24
,并且我必须将它们替换为24/12/2016
.
我可以用什么方法sed -i
来做到这一点吗?
输入示例:
节日或纪念日 宗教团体日期 附加说明 *Rosh Hashanah(新年) 犹太教 2014 年 9 月 25 日 - 2014 年 9 月 26 日 指定观察员非工作日 Navaratri/Dassehra 印度教 9 月 2014 年 10 月 3 日
*Yom Kippur(赎罪日)犹太人 2014 年 10 月 4 日,指定观察员非工作日
赞助会议 名称 地点 会议日期 2017 IEEE 传感器应用研讨会 (SAS) 美国 2017-03-13, 2017-03-14, 2017-03-15 2017 IEEE 国际医疗测量和应用研讨会 (MeMeA) 美国 2017-05 -07至2017-05-10 2017年IEEE国际仪器仪表与测量技术会议(I
这就是我到目前为止所尝试过的。
sed -i -e 's/\([0-9]\{4\}\)-\(01|Jan\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(02|Feb\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(03|Mar\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(04|Apr\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(05|May\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(06|Jun\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(07|Jul\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(08|Aug\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(09|Sep\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(10|Oct\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(11|Nov\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
sed -i -e 's/\([0-9]\{4\}\)-\(12|Dec\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
答案1
如果您有权访问 GNU date
(Linux 系统上的默认设置),您可以执行以下操作:
$ sed -E 's/(.*)-([a-z]+)(.+)/\2\3-\1/i' file |
while read d; do date -d "$d" +%d/%m/%y; done
24/12/16
24/12/16
这会将行更改为2016-Dec-24
(Dec-24-2016
GNU 可以理解的格式date
),保留行2016-12-24
(GNU 日期已经理解的格式),然后将每一行作为输入日期字符串传递给date
.它不会就地执行此操作,也不会使用sed -i
但几乎可以肯定是最简单的方法。
如果你真的需要使用 来执行此操作sed
,您可以列出所有月份和相应的数字:
$ for m in {1..12}; do printf '%s %s\n' "$m" $(date -d "$m/1/2016" +%b); done
1 Jan
2 Feb
3 Mar
4 Apr
5 May
6 Jun
7 Jul
8 Aug
9 Sep
10 Oct
11 Nov
12 Dec
将其另存为months
,然后迭代它以修改您的文件:
while read num mon; do
sed -Ei "s/$mon/$num/; s#(.*)-(.*)-(.*)#\3/\2/\1#" file
done < months
或者,如果您的 sed 实现需要单独-e
:
while read num mon; do
sed -i -e "s/$mon/$num/" -Ee 's#(.*)-(.*)-(.*)#\3/\2/\1#' file
done < months
第一个替换将用相应的数字替换所有字母月份名称,第二个替换将移动内容以获得您想要的格式。
答案2
我在正则表达式方面看到的唯一错误是,在基本(BRE)模式下,|
是文字 - 你需要\|
将其设为逻辑“或”,\(01\|Jan\)
等等。
如果您的版本支持,-e
那么我看不出有任何充分的理由进行多次调用- 您只需在一次调用中sed
链接即可。-e <expr1> -e <expr2> ...
所以
sed -i \
-e 's/\([0-9]\{4\}\)-\(01\|Jan\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(02\|Feb\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(03\|Mar\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(04\|Apr\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(05\|May\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(06\|Jun\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(07\|Jul\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(08\|Aug\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(09\|Sep\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(10\|Oct\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(11\|Nov\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' \
-e 's/\([0-9]\{4\}\)-\(12\|Dec\)-\([0-9]\{2\}\)/\3\/\2\/\1/g' $1
然而,还有更优雅的方法可以做到这一点 - 例如在 perl usingstrptime
和函数中(例如strftime
由模块提供):Time::Piece
perl -i -MTime::Piece -pe '
s|\d{4}-\d\d-\d\d?|Time::Piece->strptime($&, "%Y-%m-%d")->strftime("%Y/%m/%d")|ge;
s|\d{4}-...-\d\d?|Time::Piece->strptime($&, "%Y-%b-%d")->strftime("%Y/%m/%d")|ge;
' file
答案3
sed -r -i '
/([0-9]{4})-([[:alpha:]]{3})-([0-9]{2})/ {
s#([0-9]{4})-Jan-([0-9]{2})#\2/01/\1#g
s#([0-9]{4})-Feb-([0-9]{2})#\2/02/\1#g
s#([0-9]{4})-Mar-([0-9]{2})#\2/03/\1#g
s#([0-9]{4})-Apr-([0-9]{2})#\2/04/\1#g
s#([0-9]{4})-May-([0-9]{2})#\2/05/\1#g
s#([0-9]{4})-Jun-([0-9]{2})#\2/06/\1#g
s#([0-9]{4})-Jul-([0-9]{2})#\2/07/\1#g
s#([0-9]{4})-Aug-([0-9]{2})#\2/08/\1#g
s#([0-9]{4})-Sep-([0-9]{2})#\2/09/\1#g
s#([0-9]{4})-Oct-([0-9]{2})#\2/10/\1#g
s#([0-9]{4})-Nov-([0-9]{2})#\2/11/\1#g
s#([0-9]{4})-Dec-([0-9]{2})#\2/12/\1#g
}
s#([0-9]{4})-([0-9]{2})-([0-9]{2})#\3/\2/\1#g
' file