5

I have been trying to insert a file as the first line of another with following SED command, without much success. Each time the file is inserted after line 1. Is there a switch that will inserted before line 1?

sed -i '1r file1.txt' file2.txt

Thanks in advance.

6

The sed command r will place the contents of the specified file in the output before reading the next line of input. Unfortunately you can't specify 0 as the address for this command, so there's no way to insert the contents of a file before the first line of input (without poking around with the hold space).

You could, however, just use plain old cat. It is, after all, the command for concatenating files:

$ cat file1.txt file2.txt >out && mv out file2.txt

To be sure you're writing to a temporary file that does not already exist, one may use the mktemp utility:

$ tmp="$(mktemp)" && cat file1.txt file2.txt >"$tmp" && mv "$tmp" file2.txt

This is slightly awkward on the command line, but a good precaution in any script that needs to write to a temporary file.

  • 1
    I suggest with the use of mktemp: tmp=$(mktemp) && cat file1.txt file2.txt > $tmp && mv $tmp file2.txt ? – Danduk82 Jan 14 '17 at 21:18
  • @Danduk82 That's a reasonable suggestion. – Kusalananda Jan 14 '17 at 21:22
  • Thought of that - the text files are over 1.5 GB, takes a while. but if that is the only option! it will have to do! thank you. – user68650 Jan 14 '17 at 21:23
  • 1
    all good - did not take a long as i expected. ! 8-) – user68650 Jan 14 '17 at 21:38
  • 1
    @user68650: At a bare minimum, the functionality that you want requires reading file1.txt and file2.txt in their entirety, and writing a new version of file2.txt (containing the original content of the two files, concatenated).  mktemp and mv are very low-cost operations (except when mv really does a copy); why would you expect there to be an answer that’s more efficient than this? – Scott Jan 15 '17 at 22:43
5

With the N command

Provided that file2.txt has more than one line (else see the other section):

sed -i -e '1 { r file1.txt' -e 'N; }' file2.txt

The trick is to defer the printing of the first line with the N command.

From the manual:

N

Append the next line of input into the pattern space.

With the e command

Provided that file2.txt is not empty (else just do a copy):

sed -i -e '1 e cat file1.txt' file2.txt

GNU sed provides a e command that executes the command in parameter. The result is output is immediately.

From the manual:

e [COMMAND]

This command allows one to pipe input from a shell command into pattern space. Without parameters, the `e' command executes the command that is found in pattern space and replaces the pattern space with the output; a trailing newline is suppressed.

If a parameter is specified, instead, the `e' command interprets it as a command and sends its output to the output stream.

Note that, unlike the 'r' command, the output of the command will be printed immediately; the 'r' command instead delays the output to the end of the current cycle.

3

If you're determined to avoid cating to an explicit temporary file (or via a buffer such as sponge), then it looks like ed at least will accept a 0-address for its r command:

ed -s file2.txt << EOF
0r file1.txt
wq
EOF

or equivalently

printf '0r file1.txt\nwq\n' | ed -s file2.txt
  • 1
    Yes, ed is always a good choice when we don't need the s (streaming) of sed. – Toby Speight Nov 6 '17 at 13:09
2

If you want to insert the same file on top of multiple files within the same directory, the following based on Kusalananda's answer might be used:

for i in file*; do tmp="$(mktemp)" && cat file1 $i >"$tmp" && mv "$tmp" $i; done
  • 1
    That should work. Nice lateral thinking, and welcome to unix.se – Shadur Nov 6 '17 at 12:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.