Copying a line from one file to another in bash - 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

Related

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

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.

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

grep matching specific position in lines using words from other file

I have 2 file
file1:
12342015010198765hello
12342015010188765hello
12342015010178765hello
whose each line contains fields at fixed positions, for example, position 13 - 17 is for account_id
file2:
98765
88765
which contains a list of account_ids.
In Korn Shell, I want to print lines from file1 whose position 13 - 17 match one of account_id in file2.
I can't do
grep -f file2 file1
because account_id in file2 can match other fields at other positions.
I have tried using pattern in file2:
^.{12}98765.*
but did not work.
Using awk
$ awk 'NR==FNR{a[$1]=1;next;} substr($0,13,5) in a' file2 file1
12342015010198765hello
12342015010188765hello
How it works
NR==FNR{a[$1]=1;next;}
FNR is the number of lines read so far from the current file and NR is the total number of lines read so far. Thus, if FNR==NR, we are reading the first file which is file2.
Each ID in in file2 is saved in array a. Then, we skip the rest of the commands and jump to the next line.
substr($0,13,5) in a
If we reach this command, we are working on the second file, file1.
This condition is true if the 5 character long substring that starts at position 13 is in array a. If the condition is true, then awk performs the default action which is to print the line.
Using grep
You mentioned trying
grep '^.{12}98765.*' file2
That uses extended regex syntax which means that -E is required. Also, there is no value in matching .* at the end: it will always match. Thus, try:
$ grep -E '^.{12}98765' file1
12342015010198765hello
To get both lines:
$ grep -E '^.{12}[89]8765' file1
12342015010198765hello
12342015010188765hello
This works because [89]8765 just happens to match the IDs of interest in file2. The awk solution, of course, provides more flexibility in what IDs to match.
Using sed with extended regex:
sed -r 's#.*#/^.{12}&/p#' file2 |sed -nr -f- file1
Using Basic regex:
sed 's#.*#/^.\\{12\\}&/p#' file1 |sed -n -f- file
Explanation:
sed -r 's#.*#/^.{12}&/p#' file2
will generate an output:
/.{12}98765/p
/.{12}88765/p
which is then used as a sed script for the next sed after pipe, which outputs:
12342015010198765hello
12342015010188765hello
Using Grep
The most convenient is to put each alternative in a separate line of the file.
You can look at this question:
grep multiple patterns single file argument list too long

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