Reputation: 1216
I have filename
hello_1.0_25.tgz
a_hello_1.25.6_154.tgz
<name>_<name1>.tgz
The output which i need is
hello_1.0
a_hello_1.25.6
<name>
How can i get string before special character _
in bash (or) shell?
Upvotes: 0
Views: 113
Reputation: 41446
This awk
should do:
awk -F_ '{$NF="";sub(/_$/,"")}1' OFS=_ file
hello_1.0
a_hello_1.25.6
<name>
-F_
Sets Field Separator to _
$NF=""
Removes last field.
sub(/_$/,"")
Removes last filed separator.
1
Prints out all lines.
Upvotes: 0
Reputation: 74596
In bash, this is easy:
$ f=hello_1.0_25.tgz
$ echo "${f%_*}"
hello_1.0
${f%_*}
simply removes the _
and anything after it from the end of the variable f
.
This is more concise than other approaches that use external tools and also saves using an extra process when one isn't needed.
more tips on string manipulation in bash
Upvotes: 4
Reputation: 46813
With Bash regular expressions:
$ f=hello_1.0_25.tgz
$ if [[ $f =~ (.*)_.*\.tgz$ ]]; then echo "${BASH_REMATCH[1]}"; fi
hello_1.0
Upvotes: 0
Reputation: 84531
A slight variation on substring extraction
:
$ m="a_hello_1.25.6_154.tgz"
$ echo "${m/%_${m/#*_/}/}"
$ a_hello_1.25.6
Which basically says ${m/#*_/}
find the text following the last _
= 154.tgz
(call it stuff
); and then remove it, preceded by an underscore, from the backend of the string ${m/%_stuff/}
. For a complete expression of ${m/%_${m/#*_/}/}
.
Upvotes: 0
Reputation: 26667
Something like
sed -r 's/(.*)_.*/\1/'
Test
$ 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>
What it does?
s
substitute command
(.*)
matches anything till the last _
. Saved in \1
_.*
matches _
followed by the rest
/\1/
replaced with \1
, first capture group
OR
sed -r 's/_[^_]+$//'
Test
$ 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>
What it does?
[^_]+
Matches anything other than _
. +
quantifes the previous pattern one or more times
$
matches the end of the line
//
replaced with empty
Upvotes: 2
Reputation: 195029
this sed line should do:
sed 's/_[^_]*$//'
little test with your example:
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 can do it for sure too:
kent$ awk -F_ -v OFS="_" 'NF--' f
hello_1.0
a_hello_1.25.6
<name>
or grep if you like:
kent$ grep -Po '.*(?=_[^_]*$)' f
hello_1.0
a_hello_1.25.6
<name>
and @Tom Fenech 's bash way is nice too.
Upvotes: 1