Shell Script - read two lines of a file and read one line of another file

Say I have two files.

File1 contains:

line1 line2 line3 line4 line5 line6 line7 line8 line9 line10 

and File2 contains:

 anotherline1 anotherline2 anotherline3 

I want to make the while loop so that it displays this in File3:

 line1 line2 anotherline1 line3 line4 anotherline2 line5 line6 anotherline3 line7 line8 anotherline1 line9 line10 anotherline2 

I was looking for an answer here, but I canโ€™t figure out how to do this. I have to say that I'm pretty noob in shell scripts ...

Also: "while loop" should be to the end of file1. No matter how long File2, in fact, in my personal scenario, File2 will always be shorter than File1. The output should be: File1Line1, File1Line2, File2Line1, File1Line3, File1Line4, File2Line2 .... etc.

Any help?

note: if this has been said before, then mods, please close this question. I simply could not find the answers after searching the Internet for several hours.

EDIT: Added clarification on when to complete the loop.

+6
source share
4 answers

If I interpret your question correctly, you want

  • step file1 starts and
  • insert the next line from file2 after every two lines, going back to the top of file2 when you finish the content.

If this is the goal, you can do it with awk in several ways, but maybe the next shell fragment will do it.

 #!/usr/bin/env bash mapfile -t file2 < file2 max=${#file2[@]} while read line; do ((count++)) echo "$line" if [[ $((count%2)) == 0 ]]; then if [[ next -ge max ]]; then next=0 fi echo "${file2[next++]}" fi done < file1 

This has the downside of loading all file2 into memory as an array. If this is a problem because the file is too large, you can add some shell glop to search for specific lines each time the loop is called, although this will be very slow. Better yet, define your problem more specifically or consider alternative tools! :-)

Note that the mapfile command is bash -4-ism, so if you are on earlier Linux or OSX (which still comes with bash 3), you will need a different solution ... or upgrade to bash.

+3
source

I do not know about a convenient way to do something specific in a clean shell script. You are probably best off writing python / perl / etc. script. Something like this awk script will work, but it is somewhat dirty:

 awk '{ print; getline; print; if (!getline < "file2") { close("file2"); getline < "file2" }; print }' file1 

print; getline; print print; getline; print will print the next line from file1, then print the line and then print it. if (!getline < "file2") tries to read the next line from file2, and if it failed, closes it, implicitly opens it and reads the first line from file2. The final print will print this line from file2 (next or first).

+2
source

This awk should work:

 awk 'FNR==NR{a[++i]=$0; next} FNR%2{p=$0; curr=(FNR==1 || curr==i) ? 1 : curr+1; next} {print p ORS $0 ORS a[curr]}' file2 file1 line1 line2 anotherline1 line3 line4 anotherline2 line5 line6 anotherline3 line7 line8 anotherline1 line9 line10 anotherline2 

EDIT: Even shorter awk (thanks @geirha ):

 awk 'FNR==NR{a[n++]=$0;next}1;!(FNR%2){print a[i++%n]}' file2 file1 
+2
source

Easy to execute in the native shell - no external tools like awk are required. Open the two file descriptors associated with different files, and repeat both of them.

 while :; do read -r line1 <&3 && printf '%s\n' "$line1" || break read -r line2 <&3 && printf '%s\n' "$line2" || break read -r line3 <&4 || { exec 4<file2 && read -r line3 <&4; } printf '%s\n' "$line3" done 3<file1 4<file2 1>file3 

In this case, 3 is the number of the file descriptor on which we opened file1 , and 4 is the number of the file descriptor on which we opened file2 . 1>file3 or just >file3 , redirects the output to file descriptor 1 (aka stdout) to the output file.

You can choose other numbers if you want, although it is guaranteed that only the range between 3-9 will be free for all POSIX shells. (0-2 - stdin, stdout and stderr, above 10 can be used by the shell for its own use, although this is rarely the case in newer and more modern shells).

+1
source

Source: https://habr.com/ru/post/988337/


All Articles