There are several ways to do this properly so as to handle arbitrary input.
With GNU sed and a system that supports /dev/stdin:
sed -n "${n}{p;q;}" file2 | sed -e "$m{r/dev/stdin" -e 'd;p;}' file1
or, slightly shorter1:
sed $n'!d;q' file2 | sed -e $m'{r /dev/stdin' -e 'd;p;}' file1
With any sed and a shell that supports process substitution
sed '1h;1d;'$((m+1))'x' <(sed ${n}'!d;q' file2) file1
which could also be written as
sed ${n}'!d;q' file2 | sed '1h;1d;'$((m+1))'x' - file1
Basically, one sed invocation extracts line n from file2 which is then read by the other sed as 1st operand: it saves it into the hold buffer, deletes it and then reads the content of the 2nd operand, namely file1, exchanging buffers when on line m+1 (of the combined input).
With any sed that supports reading a script-file via -f from stdin one could run:
sed ${n}'!d;i\
'${m}'c\\
s/\\/&&/g
q' file2 | sed -f - file1
here, the 1st sed turns line n from file2 into a script-file like
${m}c\
line_n_content_here_with_any_backslash_escaped
which is then used by the 2nd sed to process file1 (namely replace line m with the following text...). Any backslashes present in the original text (along with any embedded newlines - but here there's just one line) have to be escaped because when using any of a\, i\ or c\ to add text
<backslash> characters in text shall be removed, and the following character shall be treated literally.
With any sed, you can use the always-popular substitute command making sure that the string interpolated into sed substitution escapes all reserved characters - in this particular case it's just one line so e.g.
line=$(sed ${m}'!d;s|[\/&]|\\&|g;q' file2)
then substitute:
sed ${m}'s/.*/'"$line"'/' file1
With huge input files you could run:
{ head -n $((m-1)); { head -n $((n-1)) >/dev/null; head -n 1; } <file2; head -n 1 >/dev/null; cat; } <file1
which does something like this:
print (m-1) lines from file1
discard (n-1) lines from file2
print n-th line from file2
discard m-th line from file1
print the remaining lines from file1
though some heads are dumb and won't comply with the standards so this won't work on all setups... but where it does, it trumps sed, awk and the likes in terms of speed.
1: with some shells you might need to disable history expansion for that ! to work...
also, $n and $m don't really need quoting here as they're supposed to be positive integers though it doesn't hurt either
As a GNU sed extension, the special value /dev/stdin is supported for the file name, which reads the contents of the standard inputI think GNU sed will handle /dev/stdin irrespective of system details – Sundeep Oct 06 '17 at 09:42sed -n "${n}"'{p;q}'to exit as soon as line is found – Sundeep Oct 06 '17 at 09:42/dev/stdin: could be, but my manual doesn't mention that. :) Good point about{p;q;}, edited. – Satō Katsura Oct 06 '17 at 10:36