9

I need to create the file /opt/nginx/conf.d/default.conf with this content via shell script and create the file if it doesn't exist:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    root /usr/share/nginx/html;
}

How do I write multiline content via a shell script?

I created the directory

sudo mkdir -p /opt/nginx/conf.d

But I don't know how to write a file.

terdon
  • 234,489
  • 66
  • 447
  • 667
user3142695
  • 1,529
  • 7
  • 20
  • 34
  • 1
    you can use > (to overwrite the file) or >> (to append if it already exists). example: echo "hello world" > file.txt – Rob Oct 04 '17 at 13:57
  • is that all static text, or should any part of it be substituted with a dynamic value? (e.g. hostname, port, root directory, etc) – Jeff Schaller Oct 04 '17 at 14:10
  • I just edited your question to clarify, but I may have misunderstood what you wanted. Do you want to add the contents to the file *even if it already exists*, or do you *only* want to create the file if it does not exist? What should happen if the file already exists? – terdon Oct 04 '17 at 14:19
  • 1
    duplicate of [How to append multiple lines to a file](https://unix.stackexchange.com/q/77277/44425), [Echo multiple lines of text to a file in bash?](https://superuser.com/q/351193/241386), [How to output a multiline string in Bash?](https://stackoverflow.com/q/10969953/995714) – phuclv Oct 04 '17 at 16:34

2 Answers2

20

summary : use >> to append, use [ -f file ] to test.

try

if [ ! -f myfile ]
then
   cat <<EOF > myfile
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name $server ;
    root /usr/share/nginx/html;
}
EOF
fi
  • the syntax cat <<EOF is called a "here document".
  • $server will be replace by its value, or empty if undefined.
  • as pointed out, you can use single quoted 'EOF' to avoid replacing var if any.
  • you can also have multiple echo (this could be painfull to maintain if too many echo)

    echo "## foo.conf" > foo.conf
    echo param1=hello >> foo.conf
    echo param2=world >> foo.conf
    

prepending

there is no direct prepend in bash, either use temporary file

mv file file_tmp
cat new_content file_tmp > file
rm file_tmp

or edit it

sed -i -e '1r new_file' -e 'wq' file
Christopher Schultz
  • 327
  • 1
  • 2
  • 11
Archemar
  • 31,183
  • 18
  • 69
  • 104
  • How would I prepend some multiline content to a file? – user3142695 Oct 04 '17 at 14:05
  • 1
    Another wise change to do would be to quote the here-doc limit strings, so that any words containing `$` (if present) are not treated as variables and therefore not getting expanded – Inian Oct 04 '17 at 14:08
  • @user3142695 The easiest would be to write the here-document to a separate file and then `cat` the two files together and rename the result. – Kusalananda Oct 04 '17 at 14:12
  • If one wants to do many separate `echo`s, it's still more efficient to have just one redirection, by putting them in a block: `{ echo "foo"; echo "bar"; echo "baz"; } >file` -- that way we aren't re-opening `file` every time we just want to write a single line to it, and closing it when that line is done. – Charles Duffy Oct 05 '17 at 01:46
  • Another good use of here document: `cat << EOF | sudo tee /opt/nginx/conf.d/default.conf ...` – lp1051 May 02 '18 at 14:04
3

If the /opt/nginx/conf.d/default.conf file does not exist, then print(f) the static string into the file:

[ -f /opt/nginx/conf.d/default.conf ] || printf 'server {\n    listen 80 default_server;\n    listen [::]:80 default_server;\n    server_name _;\n    root /usr/share/nginx/html;\n}\n' > /opt/nginx/conf.d/default.conf
Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
  • 1
    I'd consider `printf '%s\n' "first line" "second line"` perhaps a bit more readable; that way one doesn't need to read through the whole string to figure out where the escapes are.. – Charles Duffy Oct 05 '17 at 01:47