[bash] Bash write to file without echo?

As an exercise, does a method exist to redirect a string to a file without echo? Currently I am using

echo "Hello world" > test.txt

I know about cat and printf. I was thinking something like

> test.txt <<<"Hello world"

Of course this doesnt work, but maybe a similar command?

This question is related to bash command-line io-redirection

The answer is


There are multiple ways to do it, let's run this script called exercise.sh

#!/usr/bin/env bash

> file1.txt cat <<< "This is a here-string with random value $RANDOM"

# Or if you prefer to see what is happening and write to file as well
tee file2.txt <<< "Here is another here-string I can see and write to file"

# if you want to work multiline easily
cat <<EOF > file3.txt
You don't need to escape any quotes here, $ marks start of variables, unless escaped.
This is random value from variable $RANDOM
This is literal \$RANDOM
EOF

# Let's say you have a variable with multiline text and you want to manipulate it
a="
1
2
3
33
"

# Assume I want to have lines containing "3". Instead of grep it can even be another script
a=$(echo "$a" | grep 3)

# Then you want to write this to a file, although here-string is fine,
# if you don't need single-liner command, prefer heredoc
# Herestring. (If it's single liner, variable needs to be quoted to preserve newlines)
> file4.txt cat <<< "$a"
# Heredoc
cat <<EOF > file5.txt
$a
EOF

This is the output you should see:

$ bash exercise.sh
Here is another here-string I can see and write to file

And files should contain these:

$ ls
exercise.sh  file1.txt  file2.txt  file3.txt  file4.txt  file5.txt
$ cat file1.txt
This is a here-string with random value 20914
$ cat file2.txt
Here is another here-string I can see and write to file
$ cat file3.txt
You don't need to escape any quotes here, $ marks start of variables, unless escaped.
This is random value from variable 15899
This is literal $RANDOM
$ cat file4.txt
3
33
$ cat file5.txt
3
33

You can do this with "cat" and a here-document.

cat <<EOF > test.txt
some text
EOF

One reason for doing this would be to avoid any possibility of a password being visible in the output of ps. However, in bash and most modern shells, "echo" is a built-in command and it won't show up in ps output, so using something like this is safe (ignoring any issues with storing passwords in files, of course):

echo "$password" > test.txt

Only redirection won't work, since there's nothing to connect the now-open file descriptors. So no, there is no way like this.


I had the problem not being able to send ">" and ended up with echo!

echo "Hello world" | dd of=test.txt

There are way too many ways to possibly discuss that you probably don't care about. You can hack of course - strace bash, or do all sorts of black magic running Bash in gdb.

You actually have two completely different examples there. <<<'string' is already writing a string to a file. If anything is acceptable other than printf, echo, and cat, you can use many other commands to behave like cat (sed, awk, tee, etc).

$ cp /dev/stdin ./tmpfooblah <<<'hello world'; cat tmpfooblah
hello world

Or hell, depending on how you've compiled Bash.

$ enable -f /usr/lib/bash/print print; print 'hello world' >tmpfile

If you want to use only bash strings and redirection, in pure bash, with no hacking, and no loadables, it is not possible. In ksh93 however, it is possible.

 $ rm tmpfooblah; <<<'hello world' >tmpfooblah <##@(&!()); cat tmpfooblah
 hello world

Interestingly, I had this problem too...so I search and found this thread....I found that this worked well for me:

echo "Hello world" | grep "" > test.txt

However - When I had closed that terminal and opened a new one, I discovered that the problem went away! I wish I had kept that terminal open to compare the settings. My current terminal is a bash shell. Not sure what caused that issue to begin with - anyone?


I've a solution for bash purists.

The function 'define' helps us to assign a multiline value to a variable. This one takes one positional parameter: the variable name to assign the value.

In the heredoc, optionally there're parameter expansions too!

#!/bin/bash

define ()
{
  IFS=$'\n' read -r -d '' $1
}

BUCH="Matthäus 1"

define TEXT<<EOT
Aus dem Buch: ${BUCH}

1 Buch des Geschlechts Jesu Christi, des Sohnes Davids, des Sohnes Abrahams.
2 Abraham zeugte Isaak; Isaak aber zeugte Jakob, Jakob aber zeugte Juda und seine Brüder;
3 Juda aber zeugte Phares und Zara von der Thamar; Phares aber zeugte Esrom, Esrom aber zeugte Aram,

4 Aram aber zeugte Aminadab, Aminadab aber zeugte Nahasson, Nahasson aber zeugte Salmon,
5 Salmon aber zeugte Boas von der Rahab; Boas aber zeugte Obed von der Ruth; Obed aber zeugte Isai,
6 Isai aber zeugte David, den König. David aber zeugte Salomon von der, die Urias Weib gewesen; 

EOT

define TEXTNOEXPAND<<"EOT" # or define TEXTNOEXPAND<<'EOT'
Aus dem Buch: ${BUCH}

1 Buch des Geschlechts Jesu Christi, des Sohnes Davids, des Sohnes Abrahams.
2 Abraham zeugte Isaak; Isaak aber zeugte Jakob, Jakob aber zeugte Juda und seine Brüder;
3 Juda aber zeugte Phares und Zara von der Thamar; Phares aber zeugte Esrom, Esrom aber zeugte Aram,


4 Aram aber zeugte Aminadab, Aminadab aber zeugte Nahasson, Nahasson aber zeugte Salmon,
5 Salmon aber zeugte Boas von der Rahab; Boas aber zeugte Obed von der Ruth; Obed aber zeugte Isai,
6 Isai aber zeugte David, den König. David aber zeugte Salomon von der, die Urias Weib gewesen; 

EOT

OUTFILE="/tmp/matthäus_eins"

# Create file
>"$OUTFILE"

# Write contents
{
   printf "%s\n" "$TEXT"
   printf "%s\n" "$TEXTNOEXPAND"
} >>"$OUTFILE" 

Be lucky!


awk ' BEGIN { print "Hello, world" } ' > test.txt

would do it


The way to do this in bash is

zsh <<< '> test <<< "Hello World!"'

This is one of the interesting differences between zsh and bash: given an unchained > or >>, zsh has the good sense to hook it up to stdin, while bash does not. It would be downright useful - if it were only standard. I tried to use this to send & append my ssh key over ssh to a remote authorized_keys file, but the remote host was bash, of course, and quietly did nothing.

And that's why you should just use cat.


Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to command-line

Git is not working after macOS Update (xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools) Flutter command not found Angular - ng: command not found how to run python files in windows command prompt? How to run .NET Core console app from the command line Copy Paste in Bash on Ubuntu on Windows How to find which version of TensorFlow is installed in my system? How to install JQ on Mac by command-line? Python not working in the command line of git bash Run function in script from command line (Node JS)

Examples related to io-redirection

UTF-8 output from PowerShell Redirecting Output from within Batch file Redirect stderr to stdout in C shell Bash write to file without echo? What is /dev/null 2>&1? How to redirect both stdout and stderr to a file Redirect all output to file in Bash Send string to stdin Find and replace in file and overwrite file doesn't work, it empties the file How do I capture all of my compiler's output to a file?