【发布时间】:2011-09-16 12:23:31
【问题描述】:
我使用类似的字符串
abc_dsdsds_ss_gsgsdsfsdf_ewew_wewewewewew_adf
我需要得到一个新的,从原始字符串中删除从开头到最后出现“_”和下一个字符(可以是 3、4 或任何数字)的所有内容
所以在这种情况下我会得到
_adf
我如何使用“sed”或其他 bash 工具来做到这一点?
【问题讨论】:
我使用类似的字符串
abc_dsdsds_ss_gsgsdsfsdf_ewew_wewewewewew_adf
我需要得到一个新的,从原始字符串中删除从开头到最后出现“_”和下一个字符(可以是 3、4 或任何数字)的所有内容
所以在这种情况下我会得到
_adf
我如何使用“sed”或其他 bash 工具来做到这一点?
【问题讨论】:
sed 's/^(.*)_([^_]*)$/_\2/' < input.txt
【讨论】:
-e 标志传递给 GNU sed,您可以使用非反斜杠括号。
只需用\(_[^_]*\) 将最后一个非下划线字符分组,然后用\1 引用该组:
sed 's/^.*\(_[^_]*\)$/\1/'
结果:
$ echo abc_dsdsds_ss_gsgsdsfsdf_ewew_wewewewewew_adf | sed 's/^.*\(_[^_]*\)$/\1/'
_adf
【讨论】:
您需要修改字符串,还是只查找最后一个下划线之后的所有内容?查找最后一个 _{anything} 的正则表达式将是 /(_[^_]+)$/($ 匹配字符串的结尾),或者如果您还想匹配后面没有任何内容的尾随下划线,/(_[^_]*)$/。
除非你真的需要修改字符串而不是仅仅找到这个片段,或者你真的想从命令行而不是脚本来做这个,这个正则表达式有点简单(你用 perl 标记了这个,所以我不太确定只使用命令行而不是使用简单的脚本)。
如果您确实需要修改字符串,sed -i 's/(_[^_]+)$/\1/' myfile 或 sed -i 's/(_[^_]+)$/\1/g' myfile。 -i(编辑:我决定不要偷懒并查找正确的语法......)-i 标志只会用新文件覆盖旧文件。如果你想创建一个新文件而不是破坏旧文件,sed -e 's/.../.../g' oldfile > newfile。 s/// 之后的 g 将为您传递给 sed 的文件中的所有实例执行此操作;省略它只会替换第一个实例。
如果字符串本身不是位于行尾,而是嵌入到其他文本中。但只是用空格分隔,将$ 替换为\s,它将匹配一个空格字符(单词的结尾)。
【讨论】:
在 Perl 中,您可以这样做:
my $string = "abc_dsdsds_ss_gsgsdsfsdf_ewew_wewewewewew_adf";
if ( $string =~ m/(_[^_]+)$/ ) {
print $1;
}
[编辑] 一种 Perl 单行方法(即,可以直接从 bash 运行):
perl -lne 'm/(_[^_]+)$/ && print $1;' infile > outfile
或者使用替换:
perl -pe 's/.*(_[^_]+)$/$1/' infile > outfile
【讨论】:
一种 Perl 方式:
echo 'abc_dsdsds_ss_gsgsdsfsdf_ewew_wewewewewew_adf' | \
perl -e 'print ((split/(_)/,<>)[-2..-1])'
输出:
_adf
【讨论】:
正则表达式模式匹配是贪婪的。因此 ^.*_ 将匹配直到并包括最后一个 _ 的所有字符。然后把下划线放回去:
echo abc_dsdsds_ss_gsgsdsfsdf_ewew_wewewewewew_adf | sed 's/^.*_/_/'
【讨论】:
如果你在 bash 变量中有这样的字符串(我没有看到问题中指定的),你可以使用parameter expansion:
s="abc_dsdsds_ss_gsgsdsfsdf_ewew_wewewewewew_adf"
t="_${s##*_}"
echo "$t" # ==> _adf
【讨论】:
只是为了好玩:
echo abc_dsdsds_ss_gsgsdsfsdf_ewew_wewewewewew_adf | tr _ '\n' | tail -n 1 | rev | tr '\n' _ | rev
【讨论】: