目录

$0
$1, $2 等等
$#
$* 与 "$*"
$@ 与 "$@"
$!
$_
$$
$PPID
$?
$BASH
$BASH_VERSION
$EUID 与 $UID
$GROUPS
$HOME
$HOSTNAME
$IFS
$PATH
$OLDPWD
$PWD
$PS1
$PS2
$PS4

$0

执行 Bash 脚本时,Bash 会自动将脚本的名称保存在内置变量 $0 中。因为 $0 基于的是实际的脚本文件名称,而不是在脚本中进行硬编码,所以在重命名脚本文件的名称后,不需要修改脚本的内容。比如下面的脚本片段:

#!/bin/bash

ARGS= # 这个脚本需要  个参数.
E_BADARGS= # 传递给脚本的参数个数不对.
echo "Args number is : $#"
echo $
if [ $# -ne "$ARGS" ]
# 测试脚本的参数个数。
then
echo "Usage: $(basename $0) first-parameter second-parameter third-parameter"
exit $E_BADARGS
fi
# 开始干正事儿

在上面的代码中我们使用了 $(basename $0) 的写法,这是因为 $0 会包含脚本文件的路径,为了让输出看起来清爽一些,我用 $(basename $0) 去掉了脚本的路径名称,下面是运行的结果:

$1, $2 等等

$0, $1,$2... 被称为位置参数。所谓的位置参数(positional parameter),指的是 Shell 脚本的命令行参数(argument);同时也表示在 Shell 函数内的函数参数。它们的名称是以单个的整数来命名。出于历史的原因,当这个整数大于 9 时,就应该以大括号{} 括起来。下面是一个简单的 demo:

#!/bin/bash
echo $
echo $
echo $

$#

位置参数的个数,具体的用法请参考 $0 中的示例。

$* 与 "$*"

所有的位置参数。但是 $* 与 "$*" 的表现是不一样的,我们通过下面的 demo 来介绍其异同。
$* 提供分隔后的参数:

for arg in $*
do
echo $arg
done

$* 和 $@ 的表现是一样的。

"$*" 把所有参数看作一个字符串:

for arg in "$*"
do
echo $arg
done

$@ 与 "$@"

所有的位置参数。$@ 和 $* 的表现是一样的。
"$@" 能够提供看上去比较合理的结果:

for arg in "$@"
do
echo $arg
done

下面是 "$@" 的一个比较常见的用法如下:

if[ "$1"='node' ]; then
SCRIPT_FILE=
for ARG in "$@"
do
if[ "${ARG}"='main.js' ]; then
SCRIPT_FILE='main.js'
break
fi
done
if[ -z "$SCRIPT_FILE" ]; then
exec "$@""main.js"
exit ;
fi
fi
exec"$@"

这是在常见 nodejs 的 docker 镜像时经常使用的一段代码:

"$@" 还常常与 shift 命令一起使用来丢弃参数 $
#!/bin/bash
# 使用./test.sh 来调用这个脚本
echo "$@" #
shift
echo "$@" #
shift
echo "$@" #
# 每次 "shift" 都会丢弃$.
# "$@" 将包含剩下的参数.

还可以使用 set 命令在脚本中设置位置参数:

#!/bin/bash

set -- "First one" "second" "third:one" "" "Fifth: :one"
# 设置这个脚本的参数, $, $, 等等.
index= # 起始计数.
echo "Listing args with \"\$@\":"
for arg in "$@"
do
echo "Arg #$index = $arg"
let "index+=1"
done # $@ 把每个参数都看成是单独的单词.
echo "Arg list seen as separate words."

$!

运行在后台的最后一个作业的 PID。

$ sleep  &
[]
$ echo "$!"

如果有多个在后台运行的任务,就需要通过 $! 来获得 PID 并进行 wait:

$ sleep  &
$ pid1=$!
$ sleep &
$ pid2=$!
$ wait $pid1 # 等待第一个后台进程结束
$ wait $pid2 # 等待第二个后台进程结束

$_

这个变量保存之前执行的命令的最后一个参数的值。
把下面的代码保存在 test.sh 文件中:

#!/bin/bash

echo $_ # ./test.sh

du >/dev/null # 这么做命令行上将没有输出.
echo $_ # du ls -al >/dev/null # 这么做命令行上将没有输出.
echo $_ # -al (这是最后的参数) :
echo $_ # :

下面是一个比较常见的用法,可以直接进入创建的目录:

$ mkdir hello && cd $_

$$

脚本自身的 PID (当前 bash 进程的 PID):

$PPID

进程的 $PPID 就是这个进程的父进程的 PID。

$?

$? 保存了最后所执行的命令的退出状态码,一般表示命令执行成功或失败。当函数返回之后,$? 保存函数中最后所执行的命令的退出状态码。这就是 bash 对函数 "返回值" 的处理方法。当一个脚本退出,$? 保存了脚本的退出状态码,这个退出状态码也就是脚本中最后一个执行命令的退出状态码。 0 表示成功,其它值表示错误。

当脚本以不带参数的 exit 命令来结束时,脚本的退出状态码就由脚本中最后执行的命令来决定(就是exit之前的命令)。不带参数的exit命令与 exit $? 的效果是一样的,甚至脚本的结尾不写 exit,也与前两者的效果相同。
我们还可以把 $? 保存到变量中,从而让脚本返回其中某个命令的返回值:

#!/bin/bash
set -x
go get -d -v golang.org/x/net/html
go get -u github.com/jstemmer/go-junit-report
go test -v >& > tmp
status=$?
$GOPATH/bin/go-junit-report < tmp > test_output.xml exit ${status}

上面的程序把 go test 命令的返回值保存到了变量 status 中,并通过 exit ${status} 作为脚本的返回值。

关于退出状态
在 Linux 系统中,程序(包括脚本)的退出状态是非常有用的,只要程序执行完成,就会向 Shell 返回一个退出状态码。这个状态码是一个数值,指明了程序是否成功结束。按照惯例,退出状态码为 0 表示程序运行成功;非 0 表示程序运行失败,不同的值对应着不同的失败原因。
造成程序运行失败的原因可能是非法参数,也可能是出现了错误的条件。比如 cp 命令,退出状态码 1 表示文件没有找到,2 表示文件不可读,3 表示目标目录没有找到,4 表示目标目录不可写,5 表示一般性错误。

$BASH

Bash 的二进制程序文件的路径:

$BASH_VERSION

检查系统上安装的 Bash 版本号:

检查 $BASH_VERSION 对于判断系统上到底运行的是哪个 shell 来说是一种非常好的方法。变量 $SHELL有时候不能够给出正确的答案。

$EUID 与 $UID

$EUID 表示 "有效" 用户 ID。

$UID 表示 用户ID号,是当前用户的用户标识号, 记录在 /etc/passwd 文件中。这是当前用户的真实 id, 即使只是通过使用 su 命令来临时改变为另一个用户标识, 这个 id 也不会被改变。$UID 是一个只读变量,不能在命令行或者脚本中修改它。

$GROUPS

当前用户所属的组。
这是一个当前用户的组 id 数组, 与记录在 /etc/passwd 文件中的内容一样:

$HOME

用户的 home 目录,一般是 /home/username。

$HOSTNAME

主机名称。

$IFS

内部域分隔符。这个变量用来决定 Bash 在解释字符串时如何识别域,或者单词边界。
$IFS默认为空白(空格, 制表符,和换行符),但这是可以修改的,比如在分析逗号分隔的数据文件时,就可以设置为逗号。注意 $* 使用的是保存在 $IFS 中的第一个字符来分隔位置参数的。
$IFS 处理其他字符与处理空白字符不同的 demo:

#!/bin/bash

output_args_one_per_line()
{
for arg
do echo "[$arg]"
done
} echo "IFS=\" \""
echo "-------" IFS=" "
var=" a b c "
output_args_one_per_line $var
echo; echo "IFS=:"
echo "-----" IFS=:
var=":a::b:c:::" # 与上边一样, 但是用" "替换了":".
output_args_one_per_line $var
# 使用 : 后,冒号前后的空字符也被解析了。
exit

执行上面的脚本,结果如下:

$PATH

可执行文件的搜索路径。
当给出一个命令时,Bash 会自动生成一张哈希(hash)表,并且在这张哈希表中按照 PATH 变量中所列出的路径来搜索这个可执行命令。路径会存储在环境变量中,$PATH 变量本身就一个以冒号分隔的目录列表。通常情况下,系统都是在 /etc/profile 和 ~/.bashrc 中存储 $PATH 的定义,Ubuntu 是定义在 /etc/environment 文件中。

PATH=${PATH}:/opt/bin

将会把目录 /opt/bin 附加到当前目录列表中,在脚本中,这是一种把目录临时添加到 $PATH 中的权宜之计。当这个脚本退出时,$PATH 将会恢复以前的值(一个子进程,比如说一个脚本,是不能够修改父进程的环境变量的)。

当前的"工作目录",通常是不会出现在 $PATH 中的,这样做的目的是出于安全的考虑。因为当前目录是不断变化的,很有可能会存在与系统工具同名的恶意程序(比如你在网上下载了一个叫 cat 的恶意程序)。这时执行 cat 命令,就会运行当前目录下的 cat 恶意程序(把当前目录放在 PATH 变量的靠前位置的情况)。
还有一种情况,比如我们经常会自己用c语言或者其它的语言写一些程序,然后编译、链接为可执行文件。假如我们的可执行文件是做一些不可恢复性的操作,比如删除文件,格式化磁盘之类的。而这些文件名字又恰巧和我们系统 $PATH 下的某些常用可执行文件名字相同时,那么结果会出乎我们的意料。
也就是说当前目录是总在变化的,一会我们 cd 到这儿了,一会又 cd 到另一个地方去了。这样的话,当前目录下有哪些可执行文件也会随着改变的。有时候我们不会太在意自己处于的目录位置,如果当前目录在 $PATH中,那么我们也就不清楚自己干了什么。

而 $PATH 里面则放置了一些固定的目录,这些目录是不会变化的,这样的话,当我们输入命令时,永远可以保证不会随着自己的位置改变,而导致出乎意料。

$OLDPWD

前一个工作目录,可以通过下面的命令快速的回到前一个工作目录:

$ cd -

$PWD

工作目录(你当前所在的目录),这与内置命令 pwd 的作用相同:

下面的脚本演示了如何防止误删文件:

#!/bin/bash

E_WRONG_DIRECTORY=
clear # 清屏.
TargetDirectory=/home/nick/testdir
cd $TargetDirectory
echo "Deleting stale files in $TargetDirectory." if [ "$PWD" != "$TargetDirectory" ]
then # 防止偶然删错目录.
echo "Wrong directory!"
echo "In $PWD, rather than $TargetDirectory!"
echo "Bailing out!"
exit $E_WRONG_DIRECTORY
fi rm -rf * # 删除文件
rm .[A-Za-z0-]* # 删除点文件 echo "Done."
echo "Old files deleted in $TargetDirectory."
exit

执行上面的脚本,显示的结果如下:

$PS1

这是主提示符,可以在命令行中见到它,笔者的 Ubuntu16.04 中为:

看起来有些复杂,其实是添加了一些字体颜色的设置等内容。

$PS2

第二提示符,当你需要额外输入的时候,你就会看到它,默认值为 ">":

当我们往命令行上粘贴一个多行的命令时就会看到它的身影:

$PS4

第四提示符,当我们使用 -x 选项来调用脚本时,这个提示符会出现在每行输出的开头,默认为 "+":

运行下面的脚本:

set -x
echo "Hello nick"
echo 'This will show $PS4'

参考:
Bash Internal Variables
《高级 Bash 脚本编程指南》
《Unix/Linux/OS X 中的 Shell 编程》

常见 Bash 内置变量介绍的更多相关文章

  1. BASH内置变量

    BASH内置变量 ().BASH 作用:bash的完整路径.默认为/bin/bash ().BASH_ENV 作用:仅在非交互模式中适用.在执行shell脚本时,会先检查该变量是否指定了启动 脚本,若 ...

  2. iMacros 入门教程-内置变量介绍(5)

    iMacros 的变量类型 1.!VAR0 到 !VAR9,这是系统定义的内置变量,专门给你赋值用 就是程序设定了这几个名字给你赋值 2.内建变量 就是 imacros 设定的特别作用的变量,例如 ! ...

  3. shell 脚本中常用的内置变量

    在 Bash 解释器中,内置了许多变量,这些变量的功能是解释器自带的,我们在编写shell脚本时如果能灵活的使用它们,对脚本的编写效率以及差错大有帮助, 下面一一介绍这些变量 $FUNCNAME.$L ...

  4. Linux常用基本命令:三剑客命令之-awk内置变量与自定义变量

    AWK中,变量分为两种:内置变量与自定义变量. 常见的内置变量有: FS:输入字段分隔符, 默认为空白字符 OFS:输出字段分隔符, 默认为空白字符 RS:输入记录分隔符(输入换行符), 指定输入时的 ...

  5. Linux基础教程 linux awk内置变量使用介绍

    awk是个优秀文本处理工具,可以说是一门程序设计语言.下面是兄弟连Linux培训 给大家介绍的awk内置变量. 一.内置变量表 属性 说明 $0 当前记录(作为单个变量) $1~$n 当前记录的第n个 ...

  6. awk(流程控制、内置变量、内置函数、数组)

    摘自:http://bbs.51cto.com/thread-883948-1-1.html awk(流程控制.内置变量.内置函数.数组) ... 参考其他的资料,给大家看看.一.awk流程控制语句 ...

  7. awk内置变量 awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。

    ARGC 命令行参数个数 ARGV 命令行参数排列 ENVIRON 支持队列中系统环境变量的使用 FILENAME awk浏览的文件名 FNR 浏览文件的记录数 FS 设置输入域分隔符,等价于命令行 ...

  8. 【转】awk内置变量

    awk是个优秀文本处理工具,可以说是一门程序设计语言.下面是awk内置变量. 一.内置变量表 属性 说明 $0 当前记录(作为单个变量) $1~$n 当前记录的第n个字段,字段间由FS分隔 FS 输入 ...

  9. bash内置命令的特殊性,后台任务的"本质"

    本文解释bash内置命令的特殊性.前台.后台任务的"本质",以及前.后台任务和bash进程.终端的关系.网上没类似的资料,所以都是自己的感悟和总结,如有错误,120分的期待盼请指正 ...

随机推荐

  1. maven五:查找jar包坐标,选择jar包版本

    查找jar包坐标 以spring core的jar包为例,访问http://www.mvnrepository.com/    在最上方中间,输入spring core,点击Search. 搜索结果第 ...

  2. C#语言————第四章 深入C#的String类

    *********类型转换**************** Convert与Parse的区别: Convert可以将任何内置类型转换为其他任何内置类型 XX.Parse:只能将字符串转换为XX类型例如 ...

  3. Python基础知识:字典

    1.字典中键-值为一对,keys()返回一个列表,包含字典中所有键,values()返回所有值 favorite_languages ={ 'jack':"python", 'al ...

  4. iris数据集(.csv .txt)免费下载

    我看CSDN下载的iris数据集都需要币,我愿意免费共享,希望下载后的朋友们给我留个言 分享iris数据集(供学习使用): 链接: https://pan.baidu.com/s/1Knsp7zn-C ...

  5. VMWare:vSphere6 企业版参考序列号

    HV4WC-01087-1ZJ48-031XP-9A843 NF0F3-402E3-MZR80-083QP-3CKM2 4F6FX-2W197-8ZKZ9-Y31ZM-1C3LZ JZ2E9-6D2D ...

  6. February 4th, 2018 Week 6th Sunday

    Hope clouds observation. 心怀希望会蒙蔽双眼,影响判断. Almost every of us thinks we would be the master of our liv ...

  7. 软件工程实践_Task2_sudoku

    软工实践_Task2 标签(空格分隔): 软工实践 相关要求:第二次作业--个人项目实战 github:传送门 解题思路 先是一点杂谈. 首先,看完作业要求之后,心里先有个大概的框架. 语言:C++ ...

  8. web自动化-窗口句柄及位置变化

    在进行web自动化时,很容易会遇到多窗口进行切换测试,下面就对多窗口的一些句柄和切换及窗口句柄顺序简单总结一下 from selenium import webdriver driver = webd ...

  9. box-shadow的动效制作

    突然发现原来box-shadow的功能很强大,还能做动效,下面整理下box-shadow几个效果 案例1:hover效果 <a href="/app/list">WEB ...

  10. 使用idea搭建SSM框架

    搭建个SSM框架居然花费了我好长时间!特此记录! 需要准备的环境: idea 2017.1 jdk1.8 Maven 3.3.9  请提前将idea与Maven.jdk配置好,本次项目用的都是比较新的 ...