Remove one or more fields, delimited by a "-", at end of line

with sed you can do:

sed -E 's/(-[^-]*){2}$//' infile

match a pattern like -anything twice (...){2} from end $ of every line and remove it.


$ sed 's/-[[:alnum:]]*-[[:alnum:]]*$//' file
bucket,abc-def-ghi
bucket,dde-wwq-ooi
instance,jkl-mno-1-zzz
disk,pqr-stu-10-kuy

This uses sed to match the last two dash-delimited substrings on each line and remove them. [[:alnum:]] will match any alphanumeric character.

You may shorten it down to

sed 's/\(-[[:alnum:]]*\)\{2\}$//' file

i.e., match and delete two sets of -[[:alnum:]]* ath the end of each line.

With GNU awk, you could also do

$ awk -F '-' 'BEGIN { OFS=FS } { NF -= 2; print }' file
bucket,abc-def-ghi
bucket,dde-wwq-ooi
instance,jkl-mno-1-zzz
disk,pqr-stu-10-kuy

but changing NF like this is not portable, and should be avoided (there's no guarantee that it changes the current record). It would not work with BSD awk, for example.

With standard awk, without resorting to using sub() (which would be to just mimic sed), you would have to recreate the current record from the fields that you'd want to use (in our case, all but the last two dash-delimited fields):

$ awk -F '-' 'BEGIN { OFS=FS } { nf = split($0,a) - 2; $0=""; for (i=1; i<=nf; ++i) $i = a[i]; print }' file
bucket,abc-def-ghi
bucket,dde-wwq-ooi
instance,jkl-mno-1-zzz
disk,pqr-stu-10-kuy

With rev and cut:

rev file | cut -d'-' -f3- | rev

Reverse the lines, cut field 3 to the end of the line and reverse the text back again.


With grep (and PCRE):

grep -Po '.*(?=(-[^-]*){2}$)' file
  • -P use perl-compatible regular expressions with a positive lookahead (?...) containing two matches of - followed by any non-- characters
  • -o print only matched parts