shell命令在bash / shell中删除特殊字符后的字符

时间:2014-12-30 09:28:06

标签: bash shell sed

我有文件名

hello_1.0_25.tgz
a_hello_1.25.6_154.tgz
<name>_<name1>.tgz

我需要的输出是

hello_1.0
a_hello_1.25.6
<name>

如何在bash(或)shell中的特殊字符_之前获取字符串?

7 个答案:

答案 0 :(得分:4)

在bash中,这很简单:

$ f=hello_1.0_25.tgz
$ echo "${f%_*}"
hello_1.0

${f%_*}只是从变量_的末尾删除f及其后的所有内容。

这比使用外部工具的其他方法更简洁,并且在不需要时可以节省额外的流程。

more tips on string manipulation in bash

答案 1 :(得分:2)

这样的东西
sed -r 's/(.*)_.*/\1/'

<强>测试

$ echo "hello_1.0_25.tgz" | sed -r 's/(.*)_.*/\1/'
hello_1.0
$ echo "a_hello_1.25.6_154.tgz" | sed -r 's/(.*)_.*/\1/'
a_hello_1.25.6
$ echo "<name>_<name1>.tgz" | sed -r 's/(.*)_.*/\1/'
<name>

它的作用是什么?

  • s替换命令

  • (.*)匹配到最后_的所有内容。已保存在\1

  • _.*匹配_,其次是

  • /\1/已替换为\1,第一个捕获组

sed -r 's/_[^_]+$//'

<强>测试

$ echo "hello_1.0_25.tgz" | sed -r 's/_[^_]+$//'
hello_1.0
$ echo "a_hello_1.25.6_154.tgz"  | sed -r 's/_[^_]+$//'
a_hello_1.25.6
$ echo "<name>_<name1>.tgz"   | sed -r 's/_[^_]+$//'
<name>

它的作用是什么?

  • [^_]+匹配_以外的任何内容。 +量化先前的模式一次或多次

  • $匹配行尾

  • //替换为空

答案 2 :(得分:1)

这个 sed 行应该:

sed 's/_[^_]*$//' 
用你的例子进行小测试:

kent$  cat f
hello_1.0_25.tgz
a_hello_1.25.6_154.tgz
<name>_<name1>.tgz

kent$  sed 's/_[^_]*$//' f
hello_1.0
a_hello_1.25.6
<name>

awk 也可以肯定地做到这一点:

kent$  awk -F_ -v OFS="_" 'NF--' f
hello_1.0
a_hello_1.25.6
<name>

grep 如果您愿意:

kent$  grep -Po '.*(?=_[^_]*$)' f
hello_1.0
a_hello_1.25.6
<name>

和@Tom Fenech的bash方式也很不错。

答案 3 :(得分:0)

awk应该:

awk  -F_ '{$NF="";sub(/_$/,"")}1' OFS=_ file
hello_1.0
a_hello_1.25.6
<name>

-F_将字段分隔符设置为_
$NF=""删除最后一个字段 sub(/_$/,"")删除最后提交的分隔符。
1打印出所有行。

答案 4 :(得分:0)

substring extraction略有变化:

$ m="a_hello_1.25.6_154.tgz"
$ echo "${m/%_${m/#*_/}/}"
$ a_hello_1.25.6

基本上说${m/#*_/} 会在最后_ = 154.tgz后面找到文字(称之为stuff);然后从字符串的后端 ${m/%_stuff/}中删除它,前面加下划线。完整表达${m/%_${m/#*_/}/}

答案 5 :(得分:0)

试试这个。

sed 's/\(.*\)_\.*/\1/g' file_name

答案 6 :(得分:0)

使用Bash正则表达式:

$ f=hello_1.0_25.tgz
$ if [[ $f =~ (.*)_.*\.tgz$ ]]; then echo "${BASH_REMATCH[1]}"; fi
hello_1.0