选型总结

场景 推荐方式
单行字符串 printf '%s\n' "..." > file
多行内容 cat > file << 'EOF' ... EOF
追加内容 >> file
需要 root 写入 echo "..." | sudo tee file
脚本内变量展开 heredoc 不加引号:<< EOF
禁止变量展开 heredoc 加单引号:<< 'EOF'

单行字符串:推荐 printf

printf '%s\n' 'Hello, World!' > foo.txt

printf 简介

printf 在 Linux/Unix 系统上普遍可用,有两种形式:

  • 内建命令(built-in):bash、zsh、dash 等 shell 均内置,不依赖外部程序
  • 外部命令/usr/bin/printf,由 coreutils 包提供,几乎所有发行版默认安装

printf 的作用是格式化输出,语法来自 C 语言的 printf()

printf FORMAT [ARGUMENTS...]

常用格式占位符:

占位符 含义
%s 字符串
%d 整数
%f 浮点数
\n 换行
\t Tab

echo 在 bash 里需要加 -e 才能解析 \n,而 sh/dash 的 echo 行为又不同,跨 shell 不可靠;printf 行为在所有 shell 里一致,脚本中优先使用 printf

引号选择

字符串内容用单引号包裹:在交互式 shell(zsh/bash)中,双引号内的 ! 会触发历史展开(history expansion),导致引号未闭合、shell 进入等待状态(dquote>)。没有变量展开需求时,用单引号可以避免这个问题。

多行内容:推荐 heredoc

cat > file.txt << 'EOF'
Hello, World!
Line 2
$PWD 会原样保留,不展开
EOF

heredoc(here document)的优势是写在脚本里的格式与写入文件的格式完全一致,不需要手动处理换行。

单引号与双引号的区别

heredoc 起始标识符加单引号 'EOF',禁止变量展开,内容原样写入:

cat > file.txt << 'EOF'
Your working directory is $PWD.
EOF
# 文件内容:Your working directory is $PWD.

不加引号 EOF$VAR$(cmd) 会被 shell 展开:

cat > file.txt << EOF
Your working directory is $PWD.
EOF
# 文件内容:Your working directory is /home/user

同理,echo 也遵循相同规则:

echo 'Your working directory is $PWD.' >> file.txt   # $PWD 不展开
echo "Your working directory is $PWD."  >> file.txt  # $PWD 展开

追加内容

printf '%s\n' "new line" >> file.txt

> 覆盖写入,>> 追加写入。

需要 sudo 权限写入:用 tee

直接用 sudo echo > /etc/file 因为重定向在 sudo 提权前就已解析,会导致权限错误。正确做法是用 tee

# 覆盖写入
echo "content" | sudo tee /etc/config.conf > /dev/null

# 追加写入
echo "content" | sudo tee -a /etc/config.conf > /dev/null

# 多行内容
sudo tee /etc/config.conf > /dev/null << 'EOF'
[setting]
key = value
EOF

> /dev/null 是为了抑制 tee 同时输出到终端的内容。

参考