Yes, sed -i
reads and rewrites the file in full, and since the line length changes, it has to, as it moves the positions of all other lines.
...but in this case, the line length doesn't actually need to change. We can replace the hashbang line with #!/bin/sh␣␣
instead, with two trailing spaces. The OS will remove those when parsing the hashbang line. (Alternatively, use two newlines, or a newline + hash sign, both of which create extra lines the shell will eventually ignore.)
All we need to do is to open the file for writing from the start, without truncating it. The usual redirections >
and >>
can't do that, but in Bash, the read-write redirection <>
seems to work:
echo '#!/bin/sh ' 1<> foo.sh
or using dd
(these should be standard POSIX options):
echo '#!/bin/sh ' | dd of=foo.sh conv=notrunc
Note that strictly speaking, both of those rewrite the newline at the end of the line too, but it doesn't matter.
Of course, the above overwrites the start of the given file unconditionally. Adding a check that the original file has the correct hashbang is left as an exercise... Regardless, I probably wouldn't do this in production, and obviously, this won't work if you need to change the line to a longer one.
sed
command you have will deal with them faster than it takes to find and implement another solution. (And if you do have enormous shell scripts... well, it might be a good point to reconsider their structure.) – ilkkachu Aug 13 '20 at 20:00head
avoids reading the whole file? – Harv Aug 21 '20 at 19:39