unexpected result by cutting the last column with sed

Viewed 136
echo '60 test' | sed -r 's/(.*)\s+[^\s]+$/\1/'

result:

60 test

the last column is not cut. but it works pretty well with

echo '60 home' | sed -r 's/(.*)\s+[^\s]+$/\1/'

result:

60

why?

2 Answers

[^\s]+ means not backslash or s repeated 1 or more times and test contains s while home does not and so the latter matches the regexp while the former doesn't.

You should have used either of these instead to match non-space:

$ echo '60 test' | sed -r 's/(.*)\s+\S+$/\1/'
60

$ echo '60 test' | sed -r 's/(.*)\s+[^[:space:]]+$/\1/'
60

As @potong suggested in a comment, to remove the last column with sed all you really need is:

sed -E 's/\s+\S+$//'

I switched from -r to -E as -r is GNU sed only while -E is GNU or OSX/BSD sed so it's generally the better option to use BUT OSX/BSD sed won't recognize \s or \S so changing from -r to -E doesn't really make the script more portable in this case, you'd have to use this instead:

sed -E 's/[[:space:]]+[^[:space:]]+//'

and then to be completely portable to all POSIX seds it'd be:

sed 's/[[:space:]]\{1,\}[^[:space:]]\{1,\}//'

or this would behave the same if there's always 2 or more fields:

sed 's/[[:space:]]*[^[:space:]]*//'

If you are just printing the first part of your string before the space without doing any other modification, you can simply use cut

echo '60 test' | cut -d' ' -f1
60

where you define your delimiter (-d) and the field (-f) you want to select. No need to go for a complex solution using sed and doing some replacement operations.

With awk you can also print the first field:

echo '60 test' | awk '{print $1}'
60

or via grep in perl mode to have the \s taken into account

echo '60 test' | grep -oP '^.*?(?=\s)'
60
Related