Write string to a file without a shell

If you know of any other non-empty file on the system, then with POSIX sed:

sed -e 's/.*/hello world/' -e 'wtarget' -e q otherfile

With GNU sed and just your own non-empty file, you can use:

sed -i.bak -e '$ihello world' -e 'd' foo

With BSD sed, this would work instead:

sed -i.bak -e '$i\
hello world' -e d foo

If you're not using a shell then presumably the linebreak isn't an issue.


With ex, if the target file exists:

ex -c '0,$d' -c 's/^/hello world/' -c 'x' foo

This just deletes everything in the file, replaces the first line with "hello world", then writes and quits. You could do the same thing with vi in place of ex. Implementations are not required to support multiple -c options, but they generally do. For many ex implementations the requirement that the file already exist is not enforced.


Also with awk:

awk -v FN=foo -v STR="hello world" 'BEGIN{printf(STR) > FN }'

will write "hello world" to file "foo".


If there are existing files containing the bytes you want at known locations, you can assemble a file byte by byte over multiple commands with dd (in this case, alphabet contains the alphabet, but it could be a mix of input files):

dd if=alphabet bs=1 skip=7 count=1 of=test
dd if=alphabet bs=1 skip=4 count=1 seek=1 of=test
dd if=alphabet bs=1 skip=11 count=1 seek=2 of=test
dd if=alphabet bs=1 skip=11 count=1 seek=3 of=test
dd if=alphabet bs=1 skip=14 count=1 seek=4 of=test
cat test
hello

From there, just regular cp will work, or you might have been able to put it in-place to start with.


Less commonly, the mispipe command from moreutils allows constructing a shell-free pipe:

mispipe "echo 1" "tee wtarget"

is equivalent to echo 1 | tee wtarget, but returning the exit code of echo. This uses the system() function internally, which doesn't strictly require a shell to exist.


Finally, perl is a common command and will let you write arbitrary programs to do whatever you want on the command line, as will python or any other common scripting language. Similarly, if a shell just isn't "running", but it does exist, sh -c 'echo 1 > target' will work just fine.


You could use awk:

awk 'BEGIN {print "Hello" > "/tmp/file"}'

When an awk program consists of only a BEGIN statement, it just interprets that statement and doesn't process any input.

You can even parameterise this

awk -v text="World" -v file="/tmp/main" 'BEGIN {print text > file}'

Though with that syntax, you'd need to escape backslash characters. Using ARGV doesn't have the problem:

awk 'BEGIN {print ARGV[1] > ARGV[2]}' World /tmp/main