0

The task: using bash, iterate through a file (say, file1.txt), 2 lines at a time, prompting whether each found couplet should be copied to a second file (say, file2.txt). The command grep -A 1 "searchterm" file1.txt gives the sort of output I'm looking for. So the script should iterate through each couple of lines, ask whether or not to copy the couplet to a second file, then increment and do the same for the next couple of lines, and so on til the end of the file. The file contains probably around 4000 lines total, maybe 400 or so of which I want to copy to the second file.

Content of the file would look something like the following sample:

#searchterm blah
possible additional needed line 1
#searchterm blee
possible additional needed line 2
#searchterm blob
possible additional needed line 3
#searchterm bloh
possible additional needed line 4
#searchterm bluh
possible additional needed line etc

Copying to the second file would be done by cp >> obviously so as to add it to the end of the file. I think a for loop and/or maybe while might work for this. The incrementing part of it is kind of escaping me at the moment. But my bash scripting skills/knowledge are moderate at best. Input will be appreciated.

LATER EDIT Here's a start toward doing what I'm after (shamelessly pilfered from https://stackoverflow.com/questions/8314499/read-n-lines-at-a-time-using-bash):

while read -r ONE; do
    read -r TWO
    echo $ONE
    echo $TWO
    sleep 3
    # replace above sleep command with command(s) that copy lines or exit back to while loop
done < file1.txt

This reads file1.txt two lines at a time, outputting each couplet to the terminal. The sleep 3 line needs to be replaced by some routine that will ask user input such as "Would you like to copy these two lines to file2.txt? Answer y or n." If the user selects y then something like printf $ONE >>file2.txt && printf $TWO >>file2.txt gets run before returning to the while loop for the next two lines. If the user answers n then the loop just goes back to where it left off, outputting the next two lines of file1.txt to the terminal and asking the same question. Progress?

Later edit: First failed attempt at a full solution

while read -r ONE; do
    read -r TWO
    echo $ONE
    echo $TWO
    read -n 1 -p "Would you like to copy the above 2 lines to the new  file? [Y,n]" ans
        if [[ $ans == "Y" || $ans == "y" ]]; then
                printf $ONE >>file2.txt && printf $TWO >>file2.txt
        else
                echo "Resuming loop"
        fi
done < file1.txt

Doesn't work, meaning its output is not much different than just running cat file1.txt from the command line. But maybe it gives a better idea of what I'm hoping to accomplish with the script.

Yet later edit: semi-operational Further research revealed maybe I'd need something called a file descriptor to make this work. Using this link https://stackoverflow.com/questions/8886683/read-stdin-for-user-input-when-a-file-is-already-redirected-to-stdin I modified the script as follows

while read -r ONE <&3; do
    read -r TWO <&3
    echo $ONE
    echo $TWO
    read -n 1 -p "Would you like to copy the above 2 lines to the new  file? [Y,n]" ans
        if [[ $ans == "Y" || $ans == "y" ]]; then
                printf $ONE >>file2.txt && printf $TWO >>file2.txt
        else
                echo "Resuming loop"
        fi
done 3<file1.txt

This does actually allow me to copy pairs of lines from the file being read to stdin to another file. Pretty much what I want. I just need to puzzle out how to introduce newlines into the file being created so line pairs being copied over to not wind up being on the same line. Further input and explanations welcome.

10
  • "couplet" isn't a common term when talking about searching for strings in files. Are you saying you want to read two lines from a file, check whether a string appears in either line, and decide whether to write the lines/string to an output file?
    – Sotto Voce
    Jul 24, 2022 at 23:34
  • Pretty much that, yeah: copy 2 lines. Although I know that searchterm appears in every other line, in just that form, as in the sample given. Which is why grep -A 1 works to get the 2 lines needed, or couplet. Hope that makes sense.
    – MJiller
    Jul 24, 2022 at 23:44
  • The aim is that both the line containing searchterm and the line following get copied to file2.txt
    – MJiller
    Jul 24, 2022 at 23:54
  • 1
    I suggest you start with a while read loop, try to write that script and come back with your problem if you don't succeed.
    – Philippos
    Jul 25, 2022 at 6:12
  • 1
    Do you need to do it in bash? I think awk would be a better option (e.g. awk '/searchterm/ { getline var; print $0"\n"var > "file2.txt" }' infile)
    – r_31415
    Jul 25, 2022 at 6:44

2 Answers 2

0

Just change the line:

printf $ONE >>file2.txt && printf $TWO >>file2.txt

to

printf "$ONE\n" >>file2.txt && printf "$TWO\n" >>file2.txt

This should put the output of each printf statement on a new line.

0

Using Raku (formerly known as Perl_6)

raku -ne 'm/blah | blob/ ?? put($_, "\n", get) !! next;'  

#OR

raku -e 'for lines() { m/blah | blob/ ?? put($_, "\n", get) !! next};' 

OR

raku -e 'for lines.rotor(2) { .join("\n").put if m/blah | blob/ };'

#OR

raku -e 'for lines.batch(2) { .join("\n").put if m/blah | blob/ };'

Does it have to be bash? Here's an answer written in Raku. Raku's lines routine reads input lazily, so it should be pretty efficient. The first two answers return the matching line, then gets-and-returns the line that follows each match.

The third answer rotors each couplet together so they're analyzed two-lines-at a time. Since rotor drops "incomplete/partial" groupings at the end, the fourth example uses batch instead which returns partial groupings (identical to rotor(2, partial => True)).

Sample Input:

#searchterm blah
possible additional needed line 1
#searchterm blee
possible additional needed line 2
#searchterm blob
possible additional needed line 3
#searchterm bloh
possible additional needed line 4
#searchterm bluh
possible additional needed line etc

Sample Output (all four examples):

#searchterm blah
possible additional needed line 1
#searchterm blob
possible additional needed line 3

https://raku.org

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .