How to select a group lines by your content of a file in GNU/Linux?

Viewed 25

Good days. I have a problem. I have that get the lines that has a content specified. The command grep allow search a content specified of a file, but this line by line. I would like to select a content of various lines. How to do this? something as

cat -n /etc/profile | grep "
   if [ "$DISPLAY" != "" ]
   then
       xhost +si:localuser:root
   fi
"

Thank you very much.

3 Answers

Suggesting to research grep with option -z.


But better option is awk.

With awk it is possible to select a range awk '/RegExp1/,/RegExp2/' input.txt

In your case:

 awk '/if/,/fi/{print}' input.txt

Will print all lines in if fi range.


Also With awk it is possible to define record separator with RS variable. For example record separator is empty line. awk '1' RS="\n\n"

at end, I solve it, so...

sed -i "$(cat -n /etc/profile | gawk '/if \[ "\$DISPLAY" != "" \]/,/fi/{print $1}' | tr '\n' ',' | sed 's/,$//g' | sed -E 's/,(.+),/,/g')d" /etc/profile
  1. cat -n /etc/profile shows the file content and line numbers

       27    if [ -d /etc/profile.d ]; then
       28      for i in /etc/profile.d/*.sh; do
       29        if [ -r $i ]; then
       30          . $i
       31        fi
       32      done
       33      unset i
       34    fi
       35    #start
       36    if [ "$DISPLAY" != "" ]
       37    then
       38        xhost +si:localuser:root
       39    fi
       40    #end
    
  2. Thank you to @Dudi Boy this command gawk '/if \[ "\$DISPLAY" != "" \]/,/fi/{print $1}' show the lines of section specified.

       36
       37
       38
       39
    
  3. Now I replace the \n by ,: tr '\n' ','

       36,37,38,39,
    
  4. I delete the last comma (,): sed 's/,$//g'

       36,37,38,39
    
  5. And get only the first and last numbers separed by comma (,): sed -E 's/,(.+),/,/g'

       36,39
    
  6. Finally the result I execute it in a command sed: sed -i "$(cat -n /etc/profile | gawk '/if \[ "\$DISPLAY" != "" \]/,/fi/{print $1}' | tr '\n' ',' | sed 's/,$//g' | sed -E 's/,(.+),/,/g')d" /etc/profile

The result is

if [ -d /etc/profile.d ]; then
    for i in /etc/profile.d/*.sh; do
        if [ -r $i ]; then
            . $i
        fi
    done
    unset i
fi
#start
#end

Thank you very much

It is possible to accomplish the task of removing/substruct the ranged section with oneqawk command:

 gawk -i inplace '/if \[ "\$DISPLAY" != "" \]/,/fi/{next}1' /etc/profile
Related