前置

前置

我需要/opt/nginx/conf.d/default.conf通过 shell 脚本创建包含此内容的文件,如果该文件不存在则创建该文件:

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

如何通过 shell 脚本编写多行内容?

我创建了目录

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

但我不知道如何写入文件。

答案1

摘要:用于>>追加,用于[ -f file ]测试。

尝试

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
  • 该语法cat <<EOF称为“这里的文档”。
  • $server将被其值替换,如果未定义则为空。
  • 正如所指出的,您可以使用单引号'EOF'来避免替换 var(如果有)。
  • 你也可以有多个回声(如果回声太多,维护起来可能会很痛苦)

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

前置

bash 中没有直接前置,要么使用临时文件

mv file file_tmp
cat new_content file_tmp > file
rm file_tmp

或编辑它

sed -i -e '1r new_file' -e 'wq' file

答案2

如果 /opt/nginx/conf.d/default.conf 文件确实不是存在,然后将静态字符串 print(f) 到文件中:

[ -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

答案3

没有什么可以阻止您将换行符传递给echo.在单引号或双引号内,在类似 Bourne 的 shell 中,换行符并不比任何其他字符更特殊

if [ ! -e "$file" ]; then
  echo "server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name $server;
    root /usr/share/nginx/html;
}" > "$file"
fi

请注意,我们不会将最后一个行分隔符添加为echo自身。

如果要输出的文本可能包含反斜杠或以 开头-,您可能需要改用printf。要么像 for orprintf '%s\n' "text"一样自动添加尾随换行符,然后在要输出的文本中添加换行符:echoprintf %s

if [ ! -e "$file" ]; then
  printf %s "server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name $server;
    root /usr/share/nginx/html;
}
" > "$file"
fi

printf '%s\n' ...还可以将多个参数传递给printf将打印的每个参数并添加换行符,因此您可以执行以下操作:

new_lines=(
  'server {'
  '  listen 80 default_server;'
  '  listen [::]:80 default_server;'
  "  server_name $server;"
  '  root /usr/share/nginx/html;'
  '}'
)
[ -e "$file" ] || printf '%s\n' "${new_lines[@]}" > "$file"

您可以在其中决定每行使用的引用类型。

但请注意,如果没有传递任何参数,printf '%s\n'仍然会打印一个空行。在 中zsh,您可以print -rC1 --改为使用。或者你可以定义一个:

println() {
  [ "$#" -eq 0 ] || printf '%s\n' "$@"
}

辅助功能。

另请注意,如果该目标作为常规文件存在,则noclobberPOSIX shell 的选项会导致>重定向运算符失败。

所以:

set -o noblobber # same as set -C
printf '%s\n' "$newcontent" > "$file"

如果它已经存在(作为常规文件),则确保$newcontent不会写入$file;如果它是一个设备(如符号链接/dev/null)或目录或 fifo 等,$newcontent仍会写入那里;因此,它不会完全避免 TOCTOU 竞争条件,因为 shell 仍然需要首先检查文件的类型)。

为了避免以无竞争的方式写入已经存在的文件,无论其类型如何,您可以使用zsh它可以让您打开带有以下O_EXCL标志的文件:

zmodload zsh/system
(sysopen -w -o excl -u 1 -- $file && print -r -- $newcontent > $file)

1 除非前面有双引号内的反斜杠。

相关内容