INPUTAA XXX Y1Y ZZZ GG dhzrr (AAAa) XXX Y2Y ZZZ TT GGGG UUOUTPUTY1YY2YThe input lines could vary.. only the XXX before the Y1Y and the ZZZ after Y1Y is constant (they are the neighbors of XXX and ZZZ like this). Y1Y could be anything, ex.: Y1Y, Y2Y, Y1T, etc. Q: how can I get the OUTPUT with awk or sed or grep? (or are there any better tool for this?)UPDATE (problem): why doesn't it works when having . in the Y1Y?[user@notebook ~] echo 'XXX Y1Y ZZZ' | grep -Po (?<=XXX )(\w+)(?= ZZZ)Y1Y[user@notebook ~] echo 'XXX Y1.Y ZZZ' | grep -Po (?<=XXX )(\w+)(?= ZZZ)[user@notebook ~] 
How to only output a column that has constant neighbors?
awk
You can use grep and the PCRE facility it provides to do this:$ grep -Po (?<=XXX )\S+(?= ZZZ) data.txt Y1YY2YDetailsThis solution makes use of the lookbehind and lookahead feature of PCRE, which can match fixed length strings.The above looks behind every \w+ to see if it's XXX and head of every \w+ seeing if it's ZZZ. If it is then it's a match. The -o switch to grep tells it to only print the matches, i.e. \w+.Followup, can you do it with sed?I don't think that this problem can be solved using sed. There are 2 approaches as I see it.save potential matches in a side variable, if you encounter ZZZ, then print thems/XXX ..our string.. ZZZ/ ..our string../No. 1 seems like a fair amount of work so I'm not going to even attempt it. Here's what happens with approach No. 2.$ sed 's/.*XXX \(.*\) ZZZ.*/\1/' data.txt Y1YY2YAAAa YXX Y2Y ZZZ TT GGGG UUSo it can find the matches just fine, but it doesn't do anything for lines that don't match. There might be a way to instruct sed to delete these lines, in which case this would be an alternate solution.