Shell 变量进阶完全指南:位置参数、内置命令、eval 与 shift 实战详解

Shell 变量进阶知识详解

适合 Linux 运维、开发人员,涵盖特殊变量、内置命令、shift/eval 等高级用法。


一、位置参数变量(特殊变量)

在 Shell 脚本中,有一类变量由系统自动赋值,用于获取脚本运行时传入的参数、脚本自身信息等,称为位置参数变量

1.1 常用位置参数列表

变量含义
$0当前脚本的文件名(如果执行时带路径,则包含路径)
$1 ~ $9第 1 到第 9 个位置参数,${10} 表示第 10 个(必须用大括号)
$#位置参数的个数(不包括 $0
$*所有位置参数(作为一个整体字符串)
$@所有位置参数(每个作为独立字符串)
$?上一条命令的退出状态码(0 成功,非 0 失败)
$$当前 Shell 进程的 PID
$!最后一个后台进程的 PID
$_上一条命令的最后一个参数

1.2 基本用法示例

脚本 showargs.sh

bash

#!/bin/bash
echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\${10} = ${10}"
echo "\$# = $#"
echo "\$* = $*"
echo "\$@ = $@"

运行并传入 1~20 个参数:

bash

bash showargs.sh {1..20}

输出(部分省略):

text

$0 = showargs.sh
$1 = 1
$2 = 2
${10} = 10
$# = 20
$* = 1 2 3 ... 20
$@ = 1 2 3 ... 20

注意: 超过 9 的参数必须用 ${10},不能写成 $10(会被解析为 $1 后跟字符 0)。


1.3 $*$@ 的关键区别(重点)

  • 不加双引号时:两者完全一样,都是将所有参数展开为多个单词。
  • 加双引号时
    • "$*":将所有参数合并为一个字符串,各参数之间由第一个字符(通常是空格)分隔。
    • "$@":将每个参数都视为独立的字符串,保留参数中的空格和特殊字符。

示例脚本 test.sh

bash

#!/bin/bash
echo "Using \"\$*\":"
for arg in "$*"; do
    echo "  $arg"
done

echo "Using \"\$@\":"
for arg in "$@"; do
    echo "  $arg"
done

运行:

bash

bash test.sh "hello world" "foo bar"

输出:

text

Using "$*":
  hello world foo bar
Using "$@":
  hello world
  foo bar

推荐: 在需要原样传递参数给其他命令时,优先使用 "$@",它会保留每个参数的空格和引号。


1.4 其他特殊变量

$? – 上一条命令的退出状态

bash

pwd
echo $?        # 0
pwa
echo $?        # 127 (命令未找到)
$$ – 当前 Shell PID

bash

echo $$        # 例如 55654
kill -9 $$     # 杀死当前 Shell(慎用)
$! – 最后一个后台进程的 PID

bash

md5sum /dev/zero &
echo $!        # 打印后台进程的 PID
$_ – 上一条命令的最后一个参数

bash

ls /etc/hosts /etc/fstab /etc/hostname
cat $_         # 等价于 cat /etc/hostname

1.5 实战:用位置参数简化系统管理

创建 /usr/bin/ssh_ctl 脚本:

bash

#!/bin/bash
systemctl $1 sshd

赋予执行权限:

bash

chmod +x /usr/bin/ssh_ctl

使用:

bash

ssh_ctl stop
ssh_ctl status
ssh_ctl start

这样通过传入 stop/start/status 作为 $1,即可快速控制 sshd 服务。


二、Shell 内置命令详解

Bash 内置了许多常用命令,它们不依赖外部程序,执行效率高。下面重点介绍 echoevalexecreadshift

2.1 echo – 输出(带转义和换行控制)

选项:

  • -n:输出后不换行
  • -e:启用转义字符(默认不解析)

常用转义字符:

字符含义
\n换行
\t水平制表符(Tab)
\b退格(光标左移一格,若后面有字符则覆盖)

示例:

bash

echo -n "hello "; echo "world"          # 输出:hello world(不换行)
echo -e "line1\nline2"                  # 两行
echo -e "a\tb"                          # a    b
echo -e "1\b23"                         # 输出 23(退格覆盖1)
echo -e "123\b"                         # 输出 123(末尾退格无覆盖,看不出效果)

退格原理详解:

  • \b 只移动光标,不删除字符。
  • 只有后续有输出字符时,才会覆盖光标所在位置的字符。
  • 末尾的 \b 仅移动光标,不影响显示,所以视觉上无变化。

2.2 eval – 二次解析执行

eval 会将参数组合成一条新命令,然后再次交给 Shell 解析并执行。常用于动态生成命令。

示例1:输出最后一个位置参数
创建 neoval.sh

bash

#!/bin/bash
eval "echo \$$#"

执行:

bash

bash neoval.sh hello world
# 输出:world

执行过程分解:

  1. Shell 首先解析双引号内的内容:
    • \$ 转义为普通字符 $
    • $# 被解析为参数个数(这里是 2)
    • 得到字符串:echo $2
  2. evalecho $2 当作新命令执行,$2 被替换为 world,最终输出 world

示例2:动态设置环境变量

bash

eval $(ssh-agent)   # 捕获 ssh-agent 的输出并执行其中的 export 命令

这相当于在当前 Shell 中设置了 SSH_AUTH_SOCKSSH_AGENT_PID 环境变量。


2.3 read – 从标准输入读取

read 用于从键盘(或重定向)读取用户输入,并赋值给变量。

常用选项:

  • -p "提示文字":输出提示信息,等待输入
  • -s:静默模式(不显示输入内容,适合密码)
  • -t 秒数:超时时间

示例:

bash

#!/bin/sh
read -p "输入你喜欢的人:" str
echo "我猜你喜欢的人是:$str"

运行效果:

text

输入你喜欢的人:刘亦菲
我猜你喜欢的人是:刘亦菲

进阶用法: 从文件读取

bash

exec < /tmp/seq.log      # 将标准输入重定向到文件
while read line; do
    echo $line
done

2.4 exec – 替换当前 Shell 进程

exec 不创建子进程,而是用指定命令替换当前 Shell 进程。当命令执行完毕,该 Shell 进程也就终止了。

示例1:

bash

exec sleep 10    # 当前 Shell 变成 sleep 进程,10秒后退出

示例2:重定向标准输入

bash

#!/bin/bash
seq 5 > /tmp/seq.log
exec < /tmp/seq.log   # 将 stdin 重定向到文件
while read line; do
    echo $line
done

执行后输出 1 2 3 4 5(每行一个数字)。


2.5 shift – 位置参数左移

shift 使所有位置参数整体向左移动一位,$1 被丢弃,$2 变成新的 $1$3 变成 $2……同时 $# 减 1。也可以指定移动位数,如 shift 2

示例1:基本移动

bash

#!/bin/sh
echo $1    # 输出第一个参数
shift      # 左移一位
echo $1    # 输出原来的第二个参数

运行:

bash

bash shift.sh hello world
# 输出:
hello
world

示例2:处理选项参数(如 -c

bash

#!/bin/sh
if [ "$1" = "-c" ]; then
    shift       # 丢弃 -c,使 $2 变成新的 $1
fi
command="$1"
echo "准备执行命令:$command"
$command

运行:

bash

bash shift.sh -c pwd
# 输出:
准备执行命令:pwd
/root

如果用户只输入 bash shift.sh -c 而未提供命令,$1 为空,建议增加健壮性检查。

示例3:一次性左移多位

bash

#!/bin/sh
echo $1
shift 2      # 左移 2 位
echo $1

bash

bash shift.sh a b c d
# 输出:
a
c

三、综合实战:eval + shift 结合解析选项

虽然本笔记未涉及,但你可以扩展:通过循环和 shift 解析多个选项(如 -f file -v),再配合 eval 动态设置变量。


总结

知识点关键点
位置参数$0~$9${10}$#$*$@
$*$@加引号时,"$*" 为整体字符串,"$@" 为独立参数
特殊状态$?(退出码),$$(PID),$!(后台 PID),$_(最后参数)
echo-n 不换行,-e 转义,\b 退格需后续字符覆盖
eval二次解析,动态执行命令
read读取输入,-p 提示,-s 静默
exec替换当前进程或重定向 IO
shift左移位置参数,支持 shift n
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值