Sed 命令将日期字符串 'DD-03-YYYY' 替换为月份的字符串,例如'March'

Sed command to replace date string 'DD-03-YYYY' with the string for the month, e.g. 'March'

我有一个数据集,其中包含格式为 'DD-MM-YYYY' 的一长串日期。对我来说唯一重要的部分是月份,我想重新格式化这些字符串以具有月份的字符串表示形式,例如将 '23-01-1994' 替换为 'January'.

在 sed 或其他一些实用程序中是否有简化的原因将这些字符串替换为它们的月份名称等效项?

这将是一个很长很长的 sed 命令:

 sed -E -e 's/\d\d-01-\d\d\d\d/January/' \
    -e 's/\d\d-02-\d\d\d\d/February/' \
    -e 's/\d\d-03-\d\d\d\d/March/' \
    -e 's/\d\d-04-\d\d\d\d/April/' \
    ...

您可以在 Unix/Linux 中使用 date 命令代替 sed。不过要小心。 date 命令在 Mac 等 BSD 平台和 Linux.

等 GNU 平台上的工作方式完全不同

在 Mac:

$ date -j -f '%d-%m-%Y' '23-01-1994' +"%B"            
January

如果您对 awk 而不是 sed 没意见,那么这很有效:

awk -F'-' 'BEGIN { split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", month, " "); } { printf "%s-%s-%s\n", , month[int()], ; }'

解释:

首先,我们将awk 的字段分隔符更改为- 字符。这使得位置变量现在将包含日、月和年。
BEGIN 块在处理第一行之前运行。为了简单起见,我们通过 split-ing 一个 space 分隔字符串来填充 month 数组。
然后,对于每一行输入,我们输出一个格式为 %s-%s-%s 的字符串,其中 %s 将填充我们提供的变量。我们必须这样做,因为我们在 - 上拆分了输入字符串,所以我们需要重新组合它。第一个和第三个字段保持原样,但第二个字段将转换为数字并用作 select 月份文本的索引。例如,如果 </code> 包含 <code>07,我们会将其转换为数字 7 并使用 month[7] 对应于 Jul.

由于您指定了 sed,这里有一种方法可以构造适当的 sed 命令。首先,让我们从定义一个 bash 数组开始:

months=(01 Jan 02 Feb 03 Mar 04 Apr 05 May 06 Jun 07 Jul 08 Aug 09 Sep 10 Oct 11 Nov 12 Dec)

其次,让我们用所有需要的 sed 命令创建一个 shell 变量 cmd

printf -v cmd 's/[[:digit:]]{2}-%s-[[:digit:]]{4}/%s/g; ' "${months[@]}"

最后,我们使用sed:

sed -re "$cmd" input_file

举个例子:

$ echo '01-02-2003 01-12-2004' | sed -re "$cmd"
Feb Dec

更多详情

对于sed,需要12个替换命令,每个月一个。 printf 命令从 months 变量创建所有 12。

$ printf -v cmd 's/[[:digit:]]{2}-%s-[[:digit:]]{4}/%s/g; ' "${months[@]}"
$ echo "$cmd"
s/[[:digit:]]{2}-01-[[:digit:]]{4}/Jan/g; s/[[:digit:]]{2}-02-[[:digit:]]{4}/Feb/g; s/[[:digit:]]{2}-03-[[:digit:]]{4}/Mar/g; s/[[:digit:]]{2}-04-[[:digit:]]{4}/Apr/g; s/[[:digit:]]{2}-05-[[:digit:]]{4}/May/g; s/[[:digit:]]{2}-06-[[:digit:]]{4}/Jun/g; s/[[:digit:]]{2}-07-[[:digit:]]{4}/Jul/g; s/[[:digit:]]{2}-08-[[:digit:]]{4}/Aug/g; s/[[:digit:]]{2}-09-[[:digit:]]{4}/Sep/g; s/[[:digit:]]{2}-10-[[:digit:]]{4}/Oct/g; s/[[:digit:]]{2}-11-[[:digit:]]{4}/Nov/g; s/[[:digit:]]{2}-12-[[:digit:]]{4}/Dec/g; 

以上内容冗长。让我们从列表中随机取一个替代命令:

s/[[:digit:]]{2}-09-[[:digit:]]{4}/Sep/g;

这将查找任意两位数,然后是 -09-,然后是任意四位数字,并将其替换为字符串 Sep。由于最后的 g,对于在行中找到的每个这样的日期都会执行此操作。

注意 [[:digit:]] 的用法。这将匹配我们所在的任何语言环境中的任何数字。在使用 unicode 字体的现代世界中,这比旧的 [0-9] 形式更可靠。