命令替换可以把一个命令的输出作为另一个命令的参数,或者赋值给变量。这是 Shell 脚本中动态获取信息的主要方式,非常常用。
推荐使用 $() 语法:
result=$(ls)
echo $(date)
files=$(find . -name "*.txt")
旧语法,不推荐:
result=`ls`
echo `date`
$() 的优势:
now=$(date)
hostname=$(hostname)
user_count=$(who | wc -l)
echo "当前时间:$(date)"
echo "当前目录:$(pwd)"
tar -czf backup_$(date +%Y%m%d).tar.gz /data
for file in $(ls *.txt); do
echo "处理 $file"
done
$() 可以嵌套:
echo "内核版本:$(uname -r)"
echo "用户目录:$(echo $(whoami) 的家目录)"
更实用的例子:
current_ip=$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | head -1 | awk '{print $2}' | cut -d/ -f1)
反引号不能直接嵌套,需要转义:
result=`echo \`date\``
命令替换会删除末尾的换行符:
text=$(echo -e "第一行\n第二行\n第三行")
echo "$text"
输出:
第一行
第二行
第三行
用引号包裹变量可以保留内部换行符。但末尾的换行符会被删除:
text=$(echo -e "第一行\n第二行\n\n\n")
echo "[$text]"
输出:
[第一行
第二行]
biggest=$(du -sh * | sort -h | tail -1)
error_count=$(grep -c "ERROR" app.log)
unique_ips=$(awk '{print $1}' access.log | sort -u)
os=$(uname -s)
kernel=$(uname -r)
cpu=$(nproc)
memory=$(free -h | awk '/^Mem:/{print $2}')
backup_file="backup_$(date +%Y%m%d_%H%M%S).tar.gz"
log_file="app_$(date +%Y%m%d).log"
if command -v git &> /dev/null; then
echo "Git 已安装"
fi
script_dir=$(cd "$(dirname "$0")" && pwd)
pid=$(pgrep nginx)
port=$(netstat -tlnp | grep nginx | awk '{print $4}' | cut -d: -f2)
命令替换会创建子 Shell,频繁调用会影响性能:
for i in {1..100}; do
result=$(some_command)
done
如果可能,把命令移到循环外:
result=$(some_command)
for i in {1..100}; do
echo "$result"
done
命令替换捕获输出作为字符串:
result=$(echo "hello")
进程替换把输出当作文件:
diff <(ls dir1) <(ls dir2)
$(command) 是推荐的命令替换语法