Sed - how to delete everything except a specific template?

I need to remove all but 1, 2 or 3 digits (0-9 or 10-99 or 100) preceding % (I don't want to see%, though) from another output of the command and drag it to another command. I know that

sed -n '/%/p' 

will only display the line (s) containing % , but that is not what I want. How can I get rid of the rest of the unwanted text and leave only these numbers, then transfer them to another team?

+8
sed
source share
6 answers

If you're not fully attached to sed, this is exactly what grep -o does:

 grep -o '[0-9]\{1,3\}%' 
+19
source share

EDIT : I misunderstood the OP and posted the wrong answer. I changed it to an answer that I believe would solve the problem in a more general scenario.

For a file like below:

 $ cat input abc 123% 123 abc% this is 456% and nothing more 456 

Use sed -n -E 's/(^|.*[^0-9])([0-9]{1,3})%.*/\2/p' input

 $ sed -n -E 's/(^|.*[^0-9])([0-9]{1,3})%.*/\2/p' input 123 456 

The -n flag allows sed to turn off automatic line output. Then we use the -E flag, which allows us to use extended regular expressions. (In GNU sed, the flag is not -E , but -r instead).

Now comes the command s/// . The group (^|.*[^0-9]) corresponds either to the beginning of a line ( ^ ), or to a sequence of zero or more characters ( .* ) Ending with an insignificant number of char ( [^0-9] ). [0-9]\{1,3\} just matches one to three digits and is tied to a group (using group separators ( and ) ) if the group is preceded by (^|.*[^0-9]) , and then % . Then .* Matches all parameters before and after this pattern. After that, we replace everything with the second group ( ([0-9]{1,3}) ) using the backward link \2 . Since we passed -n to sed, nothing was printed, but we passed the p flag to the s/// command. The result is that if the replacement is performed, the corresponding line is displayed. Note: p is the s/// flag, not the p command, because it appears immediately after the last / .

+2
source share

sed -e 's/[^0-9]*\([0-9]*\)%.*/\1/' fixes the numbers in the group because the pattern matches all (leading and ending .* ), it is all discarded.

(my pattern matches any number of digits, as sed regular expressions do not support convenient shortcuts such as [0-9]{1,3} that you see in perlre and others, so I decided to keep it simple to illustrate the principle, about which do you care)

Edit: Correct the quote and replace the leading .* [^0-9]* to avoid the greedy matching consuming number. Once more straightforward with perlre, where you can use non-greedy .?*

0
source share

Here is my picture:

 sed "/^[0-9]{1,3}%$/ bnum; d; :num s/%//" 

If the string contains 1-3 digits followed by%, it removes% -sign. Otherwise, the entire row is deleted. So for input like

 adsf 50 52% 1 12% test% 1234% %%% 85% bye 

This gives

 52 85 
0
source share

Use awk instead of sed .

 $ cat file one two 100% three 10% four 1% five $ awk '{ for(i=1;i<=NF;i++) if ($i ~/%$/) { print $i+0} } 'file 100 10 1 

For each field, check to see if there is a % sign at the end. If yes, type the number. ($ i + 0 means conversion to integer). Minimal regex.

0
source share
 sed -n "/[0-9]\{1,2\}%/ s/^[^0-9]*\([0-9]\{1,2\}\)%.*/\1/p /100%/ s/.*/100/p " 

you need to extract 100%, because otherwise the number of hits 987% (or 123% when filtering by 1 in the 1st position) is also sent to the output

0
source share

All Articles