How to copy specific lines from file 1 after specific line from file 2? - bash

I have a file1 and a file2.
I want to copy lines 3,4,5 of file1 into file2, but after line 3.
I tried this, but it didn't work:
sed -i 3r<(sed '3,5!d' file1) file2
Any ideas? (I work with a macOS)
Example file1:
_line_1;
_line_2;
_line_3;
_line_4;
_line_5;
Example file2:
line1;
line2;
line3;
line4;
Example output
line1;
line2;
line3;
_line_3;
_line_4;
_line_5;
line4;

This might work for you (GNU sed):
sed -n '3,5p' file1 | sed '3r /dev/stdin' file2
Turn off implicit printing in the first sed invocation and pipe the results (lines 3-5) from file1 to a second sed invocation that reads in these lines after line 3 of file2.

Using a mix of ed and sed:
printf "%s\n" '3r !sed -n 3,5p file1' w | ed -s file2
Inserts the results of the sed command after line 3 of file2. Said sed prints out lines 3 through 5 of file1. Then it saves the changed file2.

With only ed if it's allowed
printf "%s\n" "kx" "r file1" "'x+3,'x+5m3" "'x+1,\$d" "w" | ed -s file2
Here the k command mark the last line of file2.
You must protect the $ to the shell.

Related

Unix/bash :Print filename as first string before each line in a log file

Looking for help on how to get append the name of the file as 1st string in each row of the file.
A file which has only content. I am trying to merge 2 files but with the content should have first string as the name of the file then row 1. etc. Lets consider 2 files with name FileA and FileB. FileA has 2 lines, FileB has 2 lines.
FileA
Tom is Cat
Jerry is Mouse
FileB
Cat is Tom
Mouse is Jerry
Expected Output of merged file
FileA Tom is Cat
FileA Jerry is Mouse
FileB Cat is Tom
FileB Mouse is Jerry.
I am struggling to find a solution to this. Please help
Use sed to substitute the filename at the beginning of each line of the file:
sed 's/^/FileA /' fileA >> mergedFile
sed 's/^/FileB /' fileB >> mergedFile
For an arbitrary number of files you can loop over all the filenames, and construct the sed substitution command dynamically using the variable with the filenames.
while read -r f
do
sed "s|^|$f |" "$f"
done < file.txt > merge.txt
Using awk and brace expansion.
awk '{print FILENAME, $0}' file{A,B} | tee mergefile
file names can be anything if that is not what you have, just put them as argument with awk
awk '{print FILENAME, $0}' filefoo filebar filemore ...
Can be done with grep also if your grep has the -H option/flag
grep -H . fileA fileB
Again filenames can be anything.
Using tee to send the output to stdout and mergefile.
If you prefer ripgrep over grep these two commands produce the same output:
$ grep --with-filename '' File*
$ rg --with-filename --no-heading --no-line-number '' File*
FileA:Tom is Cat
FileA:Jerry is Mouse
FileB:Cat is Tom
FileB:Mouse is Jerry

how to replace the first line of a file with the first line of another file [duplicate]

This question already has answers here:
Replace first few lines with first few lines from other file
(3 answers)
Closed 4 years ago.
i have 2 txt files : file1 and file2
i would like to replace the first line of file2 with the first line of file1, with a bash command
file1:
aaaaaaaa
bbbbbbbb
cccccccc
file2:
zzzzzzzz
yyyyyyyy
wwwwwwww
expected result of file2:
aaaaaaaa
yyyyyyyy
wwwwwwww
this can't be done with sed as you don't know what to replace with what...i'm right? so how to do this ?
EDIT:
so in my particular case (i do it in my openwrt router), what worked is :
sed -i "1c $(sed 1q file1)" file2
Thanks to #Sundeed for the link explaining why some commands were only displaying the results in the shell but not writing in the file : https://mywiki.wooledge.org/BashPitfalls#cat_file_.7C_sed_s.2Ffoo.2Fbar.2F_.3E_file
This might work for you (GNU sed):
sed -e '1R file1' -e '1d' file2
Read the first line of file2. Read the first line of file1 and insert it into the output, then delete the first line of file2. Now read and output the rest of file2.
Simply use head and tail for this task:
head -n 1 Input_file1 && tail -n 2 Input_file2
Output will be as follows:
aaaaaaaa
yyyyyyyy
wwwwwwww
You certainly can do this with sed, but why would you?
sed "1c\\
$(sed 1q file1)
" file2
Or with ed
f1="file1";f2="file2";printf "%s\n" '2,$d' "r $f2" '2d' "wq $f2" | ed -s "$f1"

Bash - reading two files and searching within files

I have two files, file1 and file2. I want to reach each line from file1, and then search if any of the lines in file2 is present in file1. I am using the following bash script, but it does not seem to be working. What should I change? (I am new to bash scripting).
#!/bin/bash
while read line1
do
echo $line1
while read line2
do
if grep -Fxq "line2" "$1"
then
echo "found"
fi
done < "$2"
done < "$1"
Note: Both files are text files.
Use grep -f
grep -f file_with_search_words file_with_content
Note however that if file_with_search_words contains blank lines everything will be matched. But that can be easily avoided with:
grep -f <(sed '/^$/d' file_with_search_words) file_with_content
From the man page:
-f FILE, --file=FILE
Obtain patterns from FILE, one per line. If this option is used
multiple times or is combined with the -e (--regexp) option, search
for all patterns given. The empty file contains zero patterns, and
therefore matches nothing.
You may use the command "comm", it compare two sorted files line-by-line
This command show the common lines in file1 and file2
comm -12 file1 file2
The only problem with this command is that you have to sort the files before, like this:
sort file1 > file1sorted
http://www.computerhope.com/unix/ucomm.htm
File 1
Line 1
Line 3
Line 6
Line 9
File 2
Line 3
Line 6
awk 'NR==FNR{con[$0];next} $0 in con{print $0}' file1 file2
will give you
Line 3
Line 6
that is the content in file 2 which is present in file1.
If you wish to ignore the spaces you can achieve with the below one.
awk 'NR==FNR{con[$0];next} !/^$/{$0 in con;print $0}' file1 file2

Copying a line from one file to another in bash

I'm trying to copy a line from file1 and write that line into line 10 of file2 using bash.
Here is what I have tried:
sed -e '10i' file2 <file1
You can do this using awk:
awk 'NR==1{a=$0}NR==FNR{next}FNR==10{print a}1' file1 file2
NR keeps a count of the overall line number. This is only equal to 1 for the first line of the first file. The contents of the line is stored in a variable a.
FNR keeps a count of the line number of the current file. NR and FNR are equal (i.e. we are in file1), next skips to the next line, which means that for every other line in the first file, nothing happens.
The final block is executed at line 10 of the second file, inserting the value of a. The 1 at the end is a common shorthand which means that every line of the file is printed.
Testing it out:
$ cat file1
line 1 in file1
line 2 in file1
$ cat file2
line 1 in file2
line 2 in file2
line 3 in file2
line 4 in file2
line 5 in file2
line 6 in file2
line 7 in file2
line 8 in file2
line 9 in file2
line 10 in file2
$ awk 'NR==1{a=$0}NR==FNR{next}FNR==10{print a}1' file1 file2
line 1 in file2
line 2 in file2
line 3 in file2
line 4 in file2
line 5 in file2
line 6 in file2
line 7 in file2
line 8 in file2
line 9 in file2
line 1 in file1
line 10 in file2
To overwrite the original contents of file2, you can redirect the output to a temporary file like awk '...' file1 file2 tmp && mv tmp file2.
I'm not sure where you want your lines to come from and go to, but you could do this:
sed 'NUMq;d' file1 >>file2
replacing NUM with the number of the line you want from file1 to append to file2.
EDIT
I think this is what you want:
sed -i .bak "10 i\\
`sed 1q\;d file1`
" file2
If you are using GNU sed, this:
sed -n '1p' choose-line-here.txt | sed -i '10r /dev/stdin' insert-here.txt
will insert line 1 from choose-line-here.txt after line 10 in insert-here.txt.
Changing line 10 seems to be trickier, surprisingly. I've come up with this so far:
sed -n 1p choose-line-here.txt |
sed -e '9!b' -e 'N;s/\n.*//;r /dev/stdin' insert-here.txt
The tricky part is, that the r command inserts the contents of /dev/stdin, that is, standard input, after the current line. If that is the line which is to be replaced, then I don't see a way to get rid of it without outputting a spare newline. Therefore the trick to start the insertion in the previous line, line 9 in this case.
A simpler solution for changing the target line is possible, if one relies on sed not counting the freshly read line from stdin:
sed -n 1p choose-line-here.txt |
sed -i -e '9r /dev/stdin' -e '10d' insert-here.txt
This might work for you (GNU sed & Bash):
sed $'10{e sed "1!d" file1\n;d}' file2
or another way using a pipe:
sed '1!d' file1 | sed -e '10{r /dev/stdin' -e 'd}' file2
or a third way (perhaps more intuitively but only works for a singleton replacement line):
sed '10\c'$(sed '1!d' file1) file2

Unix: One line bash command to merge 3 files together. extracting only the first line of each

I am having time with my syntax here:
I have 3 files with various content file1 file2 file3 (100+ lines). I am trying to merge them together, but only the first line of each file should be merged. The point is to do it using one line of bash code:
sed -n 1p file1 file2 file3 returns only the first line of file1
You might want to try
head -n1 -q file1 file2 file3.
It's not clear if by merge you mean concatenate or join?
In awk by joining (each first line in the files printed side by side):
$ awk 'FNR==1{printf "%s ",$0}' file1 file2 file3
1 2 3
In awk by concatenating (each first line in the files printed one after another):
$ awk 'FNR==1' file1 file2 file3
1
2
3
I suggest you use head as explained by themel's answer. However, if you insist in using sed you cannot simply pass all files to it, since they are implicitly concatenated and you lose information about what the first line is in each file respectively. So, if you really want to do it in sed, you need bash to help you out:
for f in file1 file2 file3; do sed -n 1p "$f"; done
You can avoid calling external processes by using the read built-in command:
for f in file1 file2 file3; do read l < $f; echo "$l"; done > merged.txt

Resources