简体   繁体   中英

BASH - How to retrieve rows from a file from #SOF to #EOF

How to retrieve rows from a file from #SOF to #EOF

in source.sh
#SOF
"Lorem ipsum dolor sit amet"
"Vivamus pretium enim"
"Est accumsan enim magnis"
#EOF

#SOF
"Eleifend tincidunt id justo"
"Tellus ut tincidunt vel ac a orci"
"Sapien Nullam Sed nunc"
"Vestibulum est accumsan enim"
#EOF

#SOF
"Consequat mauris mollis montes"
#EOF

I need to get 3 files

in target_1.sh
"Lorem ipsum dolor sit amet"
"Vivamus pretium enim"
"Est accumsan enim magnis"

in target_2.sh
"Eleifend tincidunt id justo"
"Tellus ut tincidunt vel ac a orci"
"Sapien Nullam Sed nunc"
"Vestibulum est accumsan enim"

in target_3.sh
"Consequat mauris mollis montes"

Tell someone how to do it? thank you for your help

You can do it with :

awk '/^#EOF$/ {do_print=0}
     do_print {print > ("target_"f_index".sh")}
     /^#SOF$/ {do_print=1; f_index++}' source.sh

Input / Output:

  • Matches example shown in question.

Explanation:

  • awk '...' : Invoke awk, a tool for manipulating text files line by line. The instructions enclosed by the set of single quotes are given to awk.
  • /^#EOF$/ {do_print=0} : The ^ is regex anchor for "start of line", and $ is anchor for "end of line". Here we are saying, if we see #EOF as the only thing on a line, turn off the printing flag do_print .
  • do_print {print > ("target_"f_index".sh")} : This is run for every line parsed by awk. If the do_print flag is set, then append the line to an output file with an index specified by f_index .
  • /^#SOF$/ {do_print=1; f_index++} /^#SOF$/ {do_print=1; f_index++} : Likewise, if we see only #SOF on a line, turn on the printing flag, and increment the f_index by one.
  • Note that it's these last 3 things are evaluated for EACH line, that's why we look for EOF first, then print the line if applicable, then look for the SOF afterwards - we don't want to print #EOF or #SOF .
  • source.sh : specify the name of the input file to awk ; save a cat.

will do it gracefully :

awk '
    /^#EOF/{l=0}
    l {
        print > "target_" file ".sh"
    }
    /^#SOF/{l=1;file++}
' source.sh

AFTER PROCESSING

$ ls -1t target_*
target_1.sh
target_2.sh
targer_3.sh

EXPLANATION

  • l {} is the same as if (l==1) {} because 1 is a true expression for awk

If you want to only use (your only one tag), try doing this :

#!/bin/bash
c=0
while read a; do
    if [[ $a =~ ^#SOF ]]; then
        l=1
        ((file++))
    fi

    [[ $a =~ ^#EOF ]] && l=0

    if [[ ! $a =~ ^#SOF ]] && ((l==1)); then
        echo $a >> "target_${file}.sh"
    fi
done < input_file

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM