Regex 在unix中使用带sed的正则表达式筛选文件
我正在记录我的工作服务器的一个Shell脚本,它接受一系列以单词“dat”开头的文件,并对所有这些文件执行特定任务。问题在于脚本使用正则表达式和sed命令筛选文件,如下所示:Regex 在unix中使用带sed的正则表达式筛选文件,regex,shell,unix,sed,Regex,Shell,Unix,Sed,我正在记录我的工作服务器的一个Shell脚本,它接受一系列以单词“dat”开头的文件,并对所有这些文件执行特定任务。问题在于脚本使用正则表达式和sed命令筛选文件,如下所示: namecmp=`grep -l $name dat*.p |sed -e "s/^\(......\)\(..\)\(..\)\(....\)\(.*\)/\1\4\3\2\5/g"| sort -t '.' -k 1.7,1.14 |sed -e "s/^\(......\)\(....\)\(..\)\(..\)\(
namecmp=`grep -l $name dat*.p |sed -e "s/^\(......\)\(..\)\(..\)\(....\)\(.*\)/\1\4\3\2\5/g"| sort -t '.' -k 1.7,1.14 |sed -e "s/^\(......\)\(....\)\(..\)\(..\)\(.*\)/\1\4\3\2\5/g" | tail -1 `
我不明白这个正则表达式到底是如何过滤掉文件的。了解由该表达式过滤的任何预期输出或示例文件都会很有帮助
有没有办法找到该表达式所接受的可能表达式?有专门的库(例如Xeger),但为此,我可以向您提供一个示例:
abcdef02122014foobarfoobarfoobar
^ ^ ^ ^ ^
| | | | |
1 2 3 4 5
变成
abcdef20140212foobarfoobarfoobar
^ ^ ^ ^ ^
| | | | |
1 4 3 2 5
然后我不知道排序做了什么,但是下一个sed只是把上面的一切重新整理好
因此,在恢复原始格式之前,正则表达式似乎用于临时更改排序行的格式。有专门为此设计的库(例如Xeger),但为此,我可以向您提供一个示例:
abcdef02122014foobarfoobarfoobar
^ ^ ^ ^ ^
| | | | |
1 2 3 4 5
变成
abcdef20140212foobarfoobarfoobar
^ ^ ^ ^ ^
| | | | |
1 4 3 2 5
然后我不知道排序做了什么,但是下一个sed只是把上面的一切重新整理好
因此,在恢复原始格式之前,正则表达式似乎用于临时更改排序行的格式。
grep-l
在文件列表(dat*.p
)中搜索正则表达式($name
,在您的情况下,或者更好:无论$name
计算结果如何)然后只打印找到它的文件名
然后,这些文件名通过sed
命令传递,该命令替换(s
替换)一些东西,即^\(……\)\(…\)\(…\)\(…\)\(…\)\(.*)
被\1\4\3\2\5
替换(因此它只是重新组合了部分文件名)。然后将转换后的文件名传递到sort
,然后再次传递到sed
,这似乎只是撤销了文件名的重新组合
最后,只取最后一个文件名(tail-1
),其余的都扔掉。这比排序所有文件名要便宜得多,但谁在乎呢;-)
实际上,此行查找与
$name
中的regexp匹配的“最后”文件的名称。“last”的含义由重新分组后的文件名排序决定;假设根据组的大小,我认为时间戳被修改了,因此它从DDMMYYYY
更改为YYYYMMDD
,这在某种程度上是有意义的。grep-l
在文件列表(dat*.p
)中搜索正则表达式($name
在您的情况下,或者更好:无论$name
的计算结果是什么)然后只打印找到它的文件名
echo "1111112233444456789" | sed -e "s/^\(......\)\(..\)\(..\)\(....\)\(.*\)/\1\4\3\2\5/g"
-> 1111114444332256789
然后,这些文件名通过sed
命令传递,该命令替换(s
替换)某些内容,即^\(…\)\(…\)\(…\)\(…\)\(…\)\(*)
被\1\4\3\2\5
替换(因此它只是重新组合了部分文件名)。然后将转换后的文件名传递到sort
,然后再次传递到sed
,这似乎只是撤销了文件名的重新组合
最后,只取最后一个文件名(tail-1
),其余的都扔掉。这比排序所有文件名要便宜得多,但谁在乎呢;-)
实际上,此行查找与$name
中的regexp匹配的“最后”文件的名称。“last”的含义由重新分组后的文件名排序决定;假设从组的大小来看,我认为时间戳被修改了,因此它从DDMMYYYY
更改为YYYYMMDD
,这在某种程度上是有意义的
echo "1111112233444456789" | sed -e "s/^\(......\)\(..\)\(..\)\(....\)\(.*\)/\1\4\3\2\5/g"
-> 1111114444332256789
说明:
Begin 111111 22 33 4444 56789
^ \(......\)\(..\)\(..\)\(....\)\(.*\)
\1 \2 \3 \4 \5
优化:
- 不需要最后一个
,因此必须删除相应的\(.*)
\5
- 最后一个
也不需要(只有一个dur可以替换为g
表示字符串的开头)^
Begin 111111 22 33 4444 56789
^ \(......\)\(..\)\(..\)\(....\)\(.*\)
\1 \2 \3 \4 \5
优化:
- 不需要最后一个
,因此必须删除相应的\(.*)
\5
- 最后一个
也不需要(只有一个dur可以替换为g
表示字符串的开头)^
\1
、\2
等引用。sed
命令本身就是简单的s/a/b/c
,它是(正如我所写的)替代(replace)。它将a
替换为b
(使用标志c
,在本例中为g
,它是“全局”的,在这里没有影响)。关于时间戳的理解很好。@Alfe我怀疑的是确切的是“s/^(…)(…)(…)(…)(.*/\1\4\3\2\5/g”,那么您应该大致阅读正则表达式。这是一个匹配6+2+2+4+x字符的regexp,将它们分组为6、2、2、4和x字符。这些组在替换中由\1
、\2
等引用。sed
命令本身就是简单的s/a/b/c
,它是(正如我所写的)替代(replace)。它将a
替换为b
(使用标志c
,在本例中为“全局”且在此没有影响的g
)。