[SOLVED] inserting lines from a file into another file as the nth line
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
inserting lines from a file into another file as the nth line
Basically what I'm trying to find out is to see if the following expression can have a file as the input and as the result to be output into another file:
Code:
sed '3~4 i string' file.txt
So instead of "string" I'd like to have lines from a certain file.
Code:
sed -e '4~4 e cat input.txt' file.txt
This doesn't do what I'm expecting it to do. After the 4th line, it inserts the whole "input.txt", and that's it. So I guess I'd need a loop. So I tried:
Code:
for i in input.txt; do sed -e '4~4 e cat $i file.txt'
Which is, of course, even worse, as it's going to insert the whole input.txt after each 4th line.
I also tried this:
Code:
while read line; do sed -e "4~4 i $line" file.txt; done < input.txt
Which inserts the same line (taken at a time) in the whole file, after each 4th line, and then it begins again with the second line from input.txt and so, again, I end up with a huge number of lines.
I'm not sure how I'm supposed to approach this problem.
I think we need a better explanation of what you're trying to accomplish.
Best would be to show us the contents (samples of the data) of both files and what you want the final result to be.
Perhaps sed is not the right tool for the job.
The first expression, sed '3~4 i string' file.txt, introduces the string "string" each 4th line, starting with the 3rd line. Instead of "string" I'd like to take the lines from a certain file and introduce them into the second file in the same way (starting with the third line and then adding the lines every 4th line).
First file:
Code:
Warum hast du mich nie gefragt,
worum es in diesem Film geht?
Und warum hab ich es dir eigentlich nie erzählt?
second file (destination):
Code:
1
00:02:44,040 --> 00:02:45,960
Why haven't you ever asked me
2
00:02:46,200 --> 00:02:49,240
what is this film about?
3
00:02:53,720 --> 00:02:58,800
And why haven't I ever told you, anyway?
The merge:
Code:
1
00:02:44,040 --> 00:02:45,960
Warum hast du mich nie gefragt,
Why haven't you ever asked me
2
00:02:46,200 --> 00:02:49,240
worum es in diesem Film geht?
what is this film about?
3
00:02:53,720 --> 00:02:58,800
Und warum hab ich es dir eigentlich nie erzählt?
And why haven't I ever told you, anyway?
Wrong tool.
I'd probably use awk as it enables the detection of file change on read, but a shell script to read and keep count of records (or use modulo) then getline from the inserts should be simple enough to test.
It seems weird that I can do it so easily with a simple string with sed, but I can't do it when the input are several lines from a file Not that I have anything against awk, I'm trying to progress in that respect too, but I'm also trying to understand more advanced sed editing.
sed is a stream editor, as I think I've pointed out before. It has a hold buffer and looping constructs, but doesn't have the logic capabilities sometimes needed.
A shifting spanner does lot of jobs, but sometimes you really need a hammer.
you need to understand how sed works at all. And you will understand better why is it not really suitable for this task (first of all because sed cannot read input from one file and put lines into the other. sed is a stream editor, it works on a single stream [only]). Learning advanced sed editing is a good idea, but will not help you in this specific case (although there can be a pure sed solution).
You ought to try another tool which can handle this situation. awk/perl/python/c/java or whatever you prefer.
GNU sed has the 'R' command. It queues a line of a file to be read and inserted into the output stream at the end of the current cycle, or when the next input line is read. Because the inserted lines don't enter the pattern space they can't be edited or manipulated. https://www.gnu.org/software/sed/man...-Commands.html
Code:
sed '2~4 R file1.txt' file2.txt
1
00:02:44,040 --> 00:02:45,960
Warum hast du mich nie gefragt,
Why haven't you ever asked me
2
00:02:46,200 --> 00:02:49,240
worum es in diesem Film geht?
what is this film about?
3
00:02:53,720 --> 00:02:58,800
Und warum hab ich es dir eigentlich nie erzählt?
And why haven 't I ever told you, anyway?
#!/bin/sh
cnt=1
while IFS= read f1
do
echo "$f1"
if [ $((cnt+=1)) -eq 4 ]
then
cnt=1
IFS= read f2 <&3
echo "$f2"
fi
done <file.txt 3<insert.txt
The while-done block is fed from file.txt via stdin (file descriptor 0) and from insert.txt via file descriptor 3 (1 and 2 are reserved for stdout and stderr).
Last edited by MadeInGermany; 08-19-2018 at 02:26 PM.
Great! Thank you, Kenhelm, for showing me such an easy solution with sed.
That doesn't mean that I'm not taking into consideration what syg00 and pan64 said. They do have a point.
It's nice to know that I can also do it with bash. I'll have to digest it first A script you suggested on another thread I understood after 6-7 months ) Not that it was too complicated, but it was good homework. I kept returning to it from time to time until I kind of got it
Warum hast du mich nie gefragt,
worum es in diesem Film geht?
Und warum hab ich es dir eigentlich nie erzählt?
... and InFile2 ...
Code:
1
00:02:44,040 --> 00:02:45,960
Why haven't you ever asked me
2
00:02:46,200 --> 00:02:49,240
what is this film about?
3
00:02:53,720 --> 00:02:58,800
And why haven't I ever told you, anyway?
... this sed ...
Code:
sed '2~4 R $InFile1' $InFile2 > $OutFile
... produced this OutFile ...
Code:
1
00:02:44,040 --> 00:02:45,960
Why haven't you ever asked me
2
00:02:46,200 --> 00:02:49,240
what is this film about?
3
00:02:53,720 --> 00:02:58,800
And why haven't I ever told you, anyway?
Well, yeah, because $InFile1 is going to be interpreted literally under the simple quotes. Why are you using variables in the first place, anyhow? Just use the files themselves, like in post #8. I'm not sure how sed handles bash variables. As far as I can tell, sed doesn't find anything in $InFile1, so there's nothing to output.
you ought to learn about quotation....
Also try to use set -xv to see what's really happening during execution.
Also you can try www.shellcheck.net to catch problems.
And if you still not found:
between 'single quotes' the variables are not evaluated, so sed will see (and wanted to use as filename) $InFile1 as is.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.