我有文件名
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中的特殊字符_
之前获取字符串?
答案 0 :(得分:4)
在bash中,这很简单:
$ f=hello_1.0_25.tgz
$ echo "${f%_*}"
hello_1.0
${f%_*}
只是从变量_
的末尾删除f
及其后的所有内容。
这比使用外部工具的其他方法更简洁,并且在不需要时可以节省额外的流程。
答案 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