我有以下类型的表:
ID date DailyFlow
a 1972-01-01 17.0265761797993
b 1972-01-02 17.200476457399
c 1972-01-03 17.2926436045271
d 1972-01-04 17.3900277599829
e 1972-01-05 17.5987080931028
f 1972-01-06 17.6334881486229
g 1972-01-07 17.7030482596626
...
我想重新格式化它们,如下所示:
YYYY DDD sim
1972 1 17.0265761797993
1972 2 17.200476457399
1972 3 17.2926436045271
1972 4 17.3900277599829
1972 5 17.5987080931028
1972 6 17.6334881486229
1972 7 17.7030482596626
1972 8 17.7204382874227
第一行包含在表中。文件是纯文本 (*.txt),带有“制表符”分隔符。ID 列是虚拟的,我想删除它!在我想要的输出中,DDD 列上的数字 (1、2、3、...) 应与相应年份的日期相符。
有人知道如何做到这一点吗(使用 bash)?谢谢!
答案1
这本来是 的工作我最终找到了一个awk
,但第二列中的替换需要gensub
,因此gawk
,默认情况下不会安装 ,所以sed
解决方案:
sed -i.bak 's/[^\t]*\t\([^-]*\)-[0-9][0-9]-[0-9]\([0-9]\)[^\t]*\t\([^\t]*\)/\1\t\2\t\3/' infile
或者,使用 ERE 缩短(感谢 user1598390):
sed -E -i.bak 's/.*([0-9]{4})-[0-9]{2}-([0-9]{2})(.*)/\1\t\2\3/' infile
-i.bak
:就地处理文件,将原始文件备份到infile.bak
sed
命令分解:
s
:断言执行替换;/
:开始模式[^\t]*
: 匹配任意数量的任意字符,不匹配\t
;\t
: 匹配一个\t
字符\(
:开始第一个捕获组[^-]*
: 匹配任意数量的任意字符,不匹配-
;\)
:停止第一个捕获组-
: 匹配一个-
字符[0-9]
: 匹配任意数字[0-9]
: 匹配任意数字-
: 匹配一个-
字符[0-9]
: 匹配任意数字\(
:开始第二个捕获组[0-9]
: 匹配任意数字\)
:停止第二个捕获组[^\t]*
: 匹配任意数量的任意字符,不匹配\t
;\t
: 匹配一个\t
字符\(
:开始第三个捕获组[^\t]*
: 匹配任意数量的任意字符,不匹配\t
;\)
:停止第三个捕获组/
:停止模式/开始替换字符串\1
: 反向引用被第一个捕获组替换\2
: 反向引用被第二个捕获组替换\3
: 反向引用被第三个捕获组替换/
:停止替换字符串/启动修饰符
示例文件的输出:
user@debian ~/tmp % cat infile
a 1972-01-01 17.0265761797993
b 1972-01-02 17.200476457399
c 1972-01-03 17.2926436045271
d 1972-01-04 17.3900277599829
e 1972-01-05 17.5987080931028
f 1972-01-06 17.6334881486229
g 1972-01-07 17.7030482596626
user@debian ~/tmp % sed 's/[^\t]*\t\([^-]*\)-[0-9][0-9]-[0-9]\([0-9]\)[^\t]*\t\([^\t]*\)/\1\t\2\t\3/' infile
1972 1 17.0265761797993
1972 2 17.200476457399
1972 3 17.2926436045271
1972 4 17.3900277599829
1972 5 17.5987080931028
1972 6 17.6334881486229
1972 7 17.7030482596626
答案2
用于awk
解析和date
格式化日期,还有什么;)
awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-d\t"$3"\"")}' your_file
显示一年中的某一天(使用%j
代替%d
或更好地%-j
代替%-d
,-
避免使用0
)
awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-j\t"$3"\"")}' your_file
例子
输入文件
% cat foo
ID date DailyFlow
a 1972-01-01 17.0265761797993
b 1972-01-02 17.200476457399
c 1972-01-03 17.2926436045271
d 1972-01-04 17.3900277599829
e 1972-01-05 17.5987080931028
f 1972-01-06 17.6334881486229
g 1972-01-07 17.7030482596626
h 1972-02-01 17.7030482596626
i 1972-02-02 17.7030482596626
输出(包含月份日期)
% awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-d\t"$3"\"")}' foo
YYYY DDD sim
1972 1 17.0265761797993
1972 2 17.200476457399
1972 3 17.2926436045271
1972 4 17.3900277599829
1972 5 17.5987080931028
1972 6 17.6334881486229
1972 7 17.7030482596626
1972 1 17.7030482596626
1972 2 17.7030482596626
输出(包含一年中的某一天)
% awk 'BEGIN {printf "%s\t%s\t%s\n","YYYY","DDD","sim"} NR != 1 {system("date -d \""$2"\" +\"%Y\t%-j\t"$3"\"")}' foo
YYYY DDD sim
1972 1 17.0265761797993
1972 2 17.200476457399
1972 3 17.2926436045271
1972 4 17.3900277599829
1972 5 17.5987080931028
1972 6 17.6334881486229
1972 7 17.7030482596626
1972 32 17.7030482596626
1972 33 17.7030482596626
答案3
使用awk
:
awk 'BEGIN{print "YYYY\tDDD\tsim"} NR!=1{printf "%s\t%s\t%s\n",substr($2,0,5),$1,$3}' file
解释
- 该
BEGIN{}
部分格式化标题行。 NR!=1
省略文件的标题行printf()
格式化输出substr($2,0,5)
从日期中删除日期和月份
输出结果如下:
YYYY DDD sim
1972 1 17.0265761797993
1972 2 17.200476457399
1972 3 17.2926436045271
1972 4 17.3900277599829
1972 5 17.5987080931028
1972 6 17.6334881486229
1972 7 17.7030482596626
答案4
仅使用bash
:
#!/bin/bash
shopt -s extglob
printf "YYYY\tDDD\tsim\n"
while IFS=$'\t' read -r first second third; do
day="$(date --date="$second" '+%j')"
printf "%s\t%s\t%s\n" "${second%%-*}" "${day##*(0)}" "${third}"
done < <(tail -n +2 foo.txt)
我们从第二行开始读取输入文件的每一行,并将制表符分隔的部分作为变量
first
,second
然后third
依次然后我们使用
bash
参数扩展来获得所需的输出模式。有关参数扩展的信息,请阅读GNU 文档。extglob
用于删除天数中的填充零。
例子 :
输入 :
ID date DailyFlow
a 1972-01-01 17.0265761797993
b 1972-01-02 17.200476457399
c 1972-01-03 17.2926436045271
d 1972-01-04 17.3900277599829
e 1972-01-05 17.5987080931028
f 1972-01-06 17.6334881486229
g 1972-01-07 17.7030482596626
h 1972-02-01 17.7030482596626
i 1972-02-02 17.7030482596626
输出 :
YYYY DDD sim
1972 1 17.0265761797993
1972 2 17.200476457399
1972 3 17.2926436045271
1972 4 17.3900277599829
1972 5 17.5987080931028
1972 6 17.6334881486229
1972 7 17.7030482596626
1972 32 17.7030482596626
1972 33 17.7030482596626