sed / regex模式搜索和替换文件名中的数字

时间:2016-05-11 03:19:24

标签: regex string awk sed grep

我有一组3个文件,用日期编码:

abc1_bbb_yyy_2_8_15.csv
abd1_bba_yzy_11_8_16.csv
aby1_qba_yay_11_21_16.csv

最后三个数字代表日期:

2815
11816
112116

我需要使用单个正则表达式过滤器提取文件名中与日期对应的数字,该过滤器也会将结果转换为MMDDYY格式:

020815
110816
112116

感谢您的帮助!

5 个答案:

答案 0 :(得分:3)

awk -F'[_.]' '{printf "%02d%02d%02d\n",$(NF-3),$(NF-2),$(NF-1)}'

答案 1 :(得分:1)

这似乎是一个有趣的问题,尝试用sed解决。

我更喜欢TessellatingHeckler的perl方法。 : - )

编辑:睡过了,我更喜欢jthill的awk方法。
技术上有趣的尝试用sed解决但不是我想长期生活的东西。

foo.dat

示例数据文件......

from datetime import datetime,timedelta
current_date=datetime.now()
currQuarter = (current_date.month - 1) / 3 + 1
dtFirstDay = datetime(current_date.year, 3 * currQuarter - 2, 1)
dtLastDay = datetime(current_date.year, 3 * currQuarter + 1, 1) + timedelta(days=-1)

样本结果

请注意,sed -r启用了常规的epxression扩展。

$ cat foo.dat
abc1_bbb_yyy_2_8_15.csv
abd1_bba_yzy_11_8_16.csv
aby1_qba_yay_11_21_16.csv
$

foo.sed

通常我不是很啰嗦。 : - )

但我认为这些评论会使目的更明确。

$ sed -rf foo.sed < foo.dat
020815
110816
112116
$ 

答案 2 :(得分:1)

正如其他人所指出的那样,sed并不是这项工作最优雅的工具。使用perl,

fn='abc1_bbb_yyy_2_8_15.csv abd1_bba_yzy_11_8_16.csv aby1_qba_yay_11_21_16.csv'
for x in $fn; do
  echo $x | perl -n -e 'printf("%02d%02d%02d\n",/(\d+)_(\d+)_(\d+)\./)'
done

如果您真的被限制使用sed,那么这就是一种方法。第一个正则表达式以前缀为下划线的数字为前缀。第二个查找数字字符串,后跟下划线或点,并删除每次出现的最后2位数字。最后一个提取6个数字的最后一个字符串,后面跟着任何东西,但后跟非数字。

for x in $fn; do
  echo $x | sed -e 's/_\([0-9]\)/_0\1/g' \
    -e 's/[0-9]*\([0-9]\{2\}\)[_.]/\1/g' \
    -e 's/.*\([0-9]\{6\}\)[^0-9]*$/\1/'
done

结果:

$ for x in $fn; do
>       echo $x | sed -e 's/_\([0-9]\)/_0\1/g' \
>         -e 's/[0-9]*\([0-9]\{2\}\)[_.]/\1/g' \
>         -e 's/.*\([0-9]\{6\}\)[^0-9]*$/\1/'
>     done
020815
110816
112116

答案 3 :(得分:0)

试试这个:

REST = cat#无论你的其他管道是什么......

( cat <<EOF
abc1_bbb_yyy_2_8_15.csv
abd1_bba_yzy_11_8_16.csv
aby1_qba_yay_11_21_16.csv
EOF
)\
| cut -d_ -f4-6 \
| cut -d. -f1 \
| sed -e 's/\([0-9][0-9]*\)/0\1/g' \
    -e 's/0\([0-9][0-9]\)/\1/g' \
    -e 's/_//g' \
| $REST

答案 4 :(得分:-2)

将文件名放入t.txt

abc1_bbb_yyy_2_8_15.csv
abd1_bba_yzy_11_8_16.csv
aby1_qba_yay_11_21_16.csv

然后

$ cat t.txt | perl -p -e 's/(?<=_)(\d)(?=_)/0\1/g' | perl -p -e 's/.*(\d\d)_(\d\d)_(\d\d)\.csv/\1\2\3/'
020815
110816
112116

这不完全是sed / awk / grep,因为sed不能做外观,我现在不想要AWK,但它是正则表达式,而且是* nixy。

[编辑:好的,不喜欢Perl的downvoters,我的方法是先用0加前缀一位数,然后提取双位数对。 sed在没有外观或非捕获组的情况下做得很难,但这里有一个sed的答案,使用@ jgreve的想法,先把楔子放在一边。这还包括YYYYMMDD格式的输出,假设所有年份都是20:

#                  #wedge        #single n to 0n            #extract __dd__mm__yy                                   to 20yymmdd
cat t.txt | sed -e 's/_/__/g' -e 's/_\([0-9]\)_/_0\1_/g' -e 's/.*__\([0-9][0-9]\)__\([0-9][0-9]\)__\([0-9][0-9]\)\.csv/20\3\2\1/'