Only using sed to select mid portion on a string

Viewed 74

I have file containing text like this

4539 DECK AAA
OO-99999999-99999999-99999999-99999999 -99999999-99999999 259800
259800 259800-99999999-99999999 4539 DECK ABC
OO-99999999-99999999-99999999-99999999 -99999999-99999999 259800
259800 259800-99999999-99999999 4539 DECK ABA
OO-99999999-99999999-99999999-99999999 -99999999-99999999 259800
259800 259800-99999999-99999999 4539 DECK ABD
OO-99999999-99999999-99999999-99999999 -99999999-99999999 259800
259800 259800-99999999-99999999

I want to extract a selected port from it. So the output must look like this. Without preceding and trailing spaces tabs

AAA 
ABC 
ABA
ABD

I used this but it select entire line after text. Is there any way using only sed. Not interested in any other solution

sed "s/.*DECK[[:blank:]](.[A-Z])*/\1/"

2 Answers

You can use

sed -n '/.*DECK[[:blank:]]*\([[:upper:]]*\).*/s//\1/p' 

Details:

  • n - suppresses default line output
  • /.*DECK[[:blank:]]*\([[:upper:]]*\).*/ - zero or more chars, DECK and then zero or more horizontal whitespaces are matched, then zero or more uppercase letters are consumed and put into Group 1, and then the rest of the string (here, line) is matched
  • s//\1/p - the match from the pattern above (empty pattern tells sed to take the one that was used previously) is replaced with the Group 1 value, and only this value is printed.

See the online demo:

#!/bin/bash
s='4539 DECK AAA                      
OO-99999999-99999999-99999999-99999999 -99999999-99999999   259800  
259800   259800-99999999-99999999 4539 DECK ABC                      
OO-99999999-99999999-99999999-99999999 -99999999-99999999   259800  
259800   259800-99999999-99999999 4539 DECK ABA                      
OO-99999999-99999999-99999999-99999999 -99999999-99999999   259800  
259800   259800-99999999-99999999 4539 DECK ABD                      
OO-99999999-99999999-99999999-99999999 -99999999-99999999   259800  
259800   259800-99999999-99999999'
sed -n '/.*DECK[[:blank:]]*\([A-Z]*\).*/s//\1/p' <<< "$s"

Output:

AAA
ABC
ABA
ABD

1st solution: With your shown samples, try using following sed here. Using -E and -n options to enable ERE and stop printing of lines respectively. Then matching everything from starting to till DECK followed by space and then creating 1st backreference to have capital letters at end of line; then in substitution part substituting it with 1st backreference value.

sed -E -n 's/.*DECK[[:space:]]+([A-Z]+$)/\1/p' Input_file


2nd solution: With awk you could try following program, written and tested with shown samples. Simple explanation would be, using match function of awk to match regex DECK [A-Z]+ look for sting DECK followed by space and followed by capital letters and print only required output out of it.

awk 'match($0,/DECK [A-Z]+/){print substr($0,RSTART+5,RLENGTH-5)}' Input_file


3rd solution: Using GNU grep try following once. Firstly using -oP option to exactly match matched regex and enable ERE respectively. matching everything till DECK space and with \K forgetting it then matching capital letters and printing them.

grep -oP '.*DECK[[:space:]]*\K[A-Z]+'  Input_file
Related