user1870829
user1870829

Reputation:

insert the contents of a file to another (in a specific line of the file that is sent)-BASH/LINUX

I tried doing it with cat and then after I type the second file I added | head -$line | tail -1 but it doesn't work because it performs cat first.

Any ideas? I need to do it with cat or something else.

Upvotes: 20

Views: 25034

Answers (5)

combinatorist
combinatorist

Reputation: 565

I like doing this with head and tail if you don't mind managing a new file:

head -n 16 file1 >  file3 &&
cat        file2 >> file3 &&
tail -n+56 file1 >> file3

You can collapse this into one line if you like. Then, if you really need it to overwrite file1, do: mv file3 file1 (optionally include && between commands).

Notes:

  • head -n 16 file1 means first 16 lines of file1
  • tail -n+56 file1 means file1 starting from line 56 to the end
  • Hence, I actually skipped lines 17 through 55 from file1.
  • Of course, if you could change 56 to 17 so no lines are skipped.
  • I prefer to mix simple head and tail commands then try a magic sed command.

Upvotes: 2

sorpigal
sorpigal

Reputation: 26106

Lots of ways to do it, but I like to to choose a way that involves making tools.

First, setup test environment

rm -rf /tmp/test
mkdir /tmp/test
printf '%s\n' {0..9} > /tmp/test/f1
printf '%s\n' {one,two,three,four,five,six,seven,eight,nine,ten} > /tmp/test/f2

Now let's make the tool, and in this first pass we'll implement it badly.

# insert contents of file $1 into file $2 at line $3
insert_at () { insert="$1" ; into="$2" ; at="$3" ; { head -n $at "$into" ; ((at++)) ; cat "$insert" ; tail -n +$at "$into" ; } ; }

Then run the tool to see the amazing results.

$ insert_at /tmp/test/f1 /tmp/test/f2 5

But wait, the result is on stdout! What about overwriting the original? No problem, we can make another tool for that.

insert_at_replace () { tmp=$(mktemp) ; insert_at "$@" > "$tmp" ; mv "$tmp" "$2" ; }

And run it

$ insert_at_replace /tmp/test/f1 /tmp/test/f2 5
$ cat /tmp/test/f2

"Your implementation sucks!"

I know, but that's the beauty of making simple tools. Let's replace insert_at with the sed version.

insert_at () { insert="$1" ; into="$2" ; at="$3" ; sed -e "${at}r ${insert}" "$into" ; }

And insert_at_replace keeps working (of course). The implementation of insert_at_replace can also be changed to be less buggy, but I'll leave that as an exercise for the reader.

Upvotes: 2

gniourf_gniourf
gniourf_gniourf

Reputation: 46903

Just for fun, and just because we all love ed, the standard editor, here's an ed version. It's very efficient (ed is a genuine text editor)!

ed -s file2 <<< $'3r file1\nw'

If the line number is stored in the variable line then:

ed -s file2 <<< "${line}r file1"$'\nw'

Just to please Zack, here's one version with less bashism, in case you don't like bash (personally, I don't like pipes and subshells, I prefer herestrings, but hey, as I said, that's only to please Zack):

printf "%s\n" "${line}r file1" w | ed -s file2

or (to please Sorpigal):

printf "%dr %s\nw" "$line" file1 | ed -s file2

As Jonathan Leffler mentions in a comment, and if you intend to use this method in a script, use a heredoc (it's usually the most efficient):

ed -s file2 <<EOF
${line}r file1
w
EOF

Hope this helps!

P.S. Don't hesitate to leave a comment if you feel you need to express yourself about the ways to drive ed, the standard editor.

Upvotes: 10

techno
techno

Reputation: 535

cat file1 >>file2

will append content of file1 to file2.

cat file1 file2

will concatenate file1 and file2 and send output to terminal.

cat file1 file2 >file3

will create or overwite file3 with concatenation of file1 and file2

cat file1 file2 >>file3

will append concatenation of file1 and file2 to end of file3.

Edit:

For trunking file2 before adding file1:

sed -e '11,$d' -i file2 && cat file1 >>file2

or for making a 500 lines file:

n=$((500-$(wc -l <file1)))
sed -e "1,${n}d" -i file2 && cat file1 >>file2

Upvotes: 4

Jonathan Leffler
Jonathan Leffler

Reputation: 755044

I'd probably use sed for this job:

line=3
sed -e "${line}r file2" file1

If you're looking to overwrite file1 and you have GNU sed, add the -i option. Otherwise, write to a temporary file and then copy/move the temporary file over the original, cleaning up as necessary (that's the trap stuff below). Note: copying the temporary over the file preserves links; moving does not (but is swifter, especially if the file is big).

line=3
tmp="./sed.$$"
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
sed -e "${line}r file2" file1 > $tmp
cp $tmp file1
rm -f $tmp
trap 0

Upvotes: 25

Related Questions