文档章节

Shell表达式

如比如比
 如比如比
发布于 2017/03/30 11:37
字数 7524
阅读 58
收藏 1

●Shell表达式

■Shell变量

    Shell变量的定义、删除变量、只读变量、变量类型

    Shell支持自定义变量。

 

定义变量

    定义变量时,变量名不加美元符号($),如:

    variableName="value"

    注意,变量名和等号之间不能有空格。同时,变量名的命名须遵循如下规则:

    首个字符必须为字母(a-z,A-Z)或下划线(_)。

    中间不能有空格,可以使用下划线(_)和数字。

    不能使用标点符号。

    不能使用bash里的关键字(可用help命令查看保留关键字)。

 

使用一个定义过的变量,只要在变量名前面加美元符号($)即可,如:

    your_name="mozhiyan"

    echo $your_name

    echo ${your_name}

    变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

    for skill in Ada Coffe Action Java

    do

        echo "I am good at ${skill}Script"

    done

    如果不给skill变量加花括号,写成echo "I am good at $skillScript",解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。

 

    推荐:给所有变量加上花括号,是个好的编程习惯。

 

注意,第二次赋值的时候不能写 $myUrl="http://www.oschina.net/",使用变量的时候才加美元符($)。

declare [-afirx][shell变量]

该指令作用主要是声明和显示已经存在的shell变量。

参    数

功    能

-a

显示或者设置数组变量

-f

仅仅使用函数名

-i

显示或者设置整型变量

-r

定义只读类型的shell变量

-x

定义shell变量,并将其输出为环境变量

 

set [+-abCdefhHklmnpPtuvx]

该指令作用主要是显示系统中已经存在的shell变量,以及设置shell变量的新变量值。

参    数

功    能

-a

标识已经修改的变量,以便输出为系统环境变量

-b

立即报告后台程序的运行状态

-C

禁止使用符合“<”、“<>”、“>&”

重写文件

-d

shell默认会记录使用过的指令,以

便加速其执行。但是,若不需要使用,

则可以使用该参数选项将此功能取消

-e

如果指令返回值不为0,则立即退出shell

-f

取消使用通配符

-h

自动记录函数所在位置

-H shell

可以利用符号“!”+ <指令编号>

的格式来执行历史中已经记录的指令

-k

指令所给的参数都会被视作该指令的环境变量

-m

使用监视模式

-n

只是读取指令,而不真正执行

-p

启动优先顺序模式

-P

执行指令时,将以实际的文件或者

目录来取代符号连接

-t

执行完随后的指令,则立即退出shell

-u

当执行该指令时,遇到未经定义过

的变量,则显示错误信息

-v

显示shell所读取的输入值

-x

使用该参数选项,会先显示该指令

以及其下的参数

+<参数选项>

取消某个set指令曾启动的参数

 

只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。

 

下面的例子尝试更改只读变量,结果报错:

#!/bin/bash

myUrl="http://see.xidian.edu.cn/cpp/shell/"

readonly myUrl

myUrl="http://see.xidian.edu.cn/cpp/danpianji/"

运行脚本,结果如下:

/bin/sh: NAME: This variable is read only.

 

readonly[-fap][变量定义]

该指令作用主要是定义只读的shell变量或者函数。

参    数

功    能

-f

定义只读函数

-a

定义只读数组变量

-p

显示系统中全部的变量列表

 

删除变量

使用 unset 命令可以删除变量。语法:

unset variable_name

变量被删除后不能再次使用;unset 命令不能删除只读变量。

 

举个例子:

#!/bin/sh

myUrl="http://www.oschina.net/"

unset myUrl

echo $myUrl

上面的脚本没有任何输出。

unset [-fv][变量或函数名称]

该指令作用主要是删除指定的shell变量和函数。

参    数

功    能

-f

仅仅删除函数

-v

仅仅删除变量

[变量或函数名称]

将要删除的shell变量或函数

 

变量类型

运行shell时,会同时存在三种变量:

1) 局部变量

局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。

 

2) 环境变量

所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。

 

3) shell变量

shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

 

■Shell特殊变量

Shell $0, $#, $*, $@, $?, $$和命令行参数

 

    特殊变量列表

变量

含义

$0

当前脚本的文件名

$n

传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。${10}

$#

传递给脚本或函数的参数个数。${#*},${#@}

$*

传递给脚本或函数的所有参数。

$@

传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,但 $* 特殊参数将整个列表作为一个参数,各个值之间用空格隔开。而 $@ 特殊参数将整个列表分隔成单独的参数。

$?

上个命令的退出状态,或函数的返回值

$$

当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。

$-

传递到脚本中的标志(使用set)

$_

之前命令的最后一个参数

$!

运行在后台的最后一个作业的进程ID(PID)

 

#!/bin/sh

# ./variable.sh aa bb

echo "number:$#"

echo "scname:$0"

echo "first :$1"

echo "second:$2"

echo "argume:$@"

 

$ ./variable.sh aa bb

number:2

scname:./variable.sh

first :aa

second:bb

argume:aa bb

 

获取最后面的参数

#!/bin/sh

# ./var2.sh aa bb

args=$#

lastargs=${!args}

echo $lastargs

echo ${!#}

echo $(eval echo "\$$#")

 

#!/bin/sh

# ./test13.sh 1 2 3 'asdf $asdfasdf'

echo "\$*=$*"

echo --------------------------

for n in "$*";do echo $n;done

 

echo ""

echo "\$@=$@"

echo --------------------------

for n in "$@";do echo $n;done

 

$ ./test13.sh 1 2 3 'asdf $asdfasdf'

$*=1 2 3 asdf $asdfasdf

--------------------------

1 2 3 asdf $asdfasdf

 

$@=1 2 3 asdf $asdfasdf

--------------------------

1

2

3

asdf $asdfasdf

 

Shell特殊变量其实是Shell的一些内部变量

$BASH

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

$ echo $BASH

/bin/bash

 

$BASH_ENV

这个环境变量会指向一个Bash的启动文件,当一个脚本被调用的时候,这个启动文件将会被读取。

 

$BASH_SUBSHELL

这个变量用来提示子shell的层次。这是一个Bash的新特性,直到版本3的Bash才被引入近来。

#!/bin/bash

# subshell.sh

echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL"

outer_variable=Outer

(

echo "Subshell level INSIDE subshell = $BASH_SUBSHELL"

inner_variable=Inner

 

echo "From subshell, \"inner_variable\" = $inner_variable"

echo "From subshell, \"outer\" = $outer_variable"

)

echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL"

if [ -z "$inner_variable" ]

then

    echo "inner_variable undefined in main body of shell"

else

    echo "inner_variable defined in main body of shell"

fi

exit 0

 

$BASH_VERSINFO[n]

这是一个含有6个元素的数组,它包含了所安装的Bash的版本信息。这与下边的$BASH_VERSION很相像,但是这个更加详细一些。

for n in 0 1 2 3 4 5

do

    echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}"

done

# BASH_VERSINFO[0] = 3                      # 主版本号.

# BASH_VERSINFO[1] = 2                     # 次版本号.

# BASH_VERSINFO[2] = 25                    # 补丁次数.

# BASH_VERSINFO[3] = 1                      # 编译版本.

# BASH_VERSINFO[4] = release                # 发行状态.

# BASH_VERSINFO[5] = x86_64-redhat-linux-gnu  # 结构体系

$BASH_VERSION

安装在系统上的Bash版本号。

bash$ echo $BASH_VERSION

3.2.25(1)-release

tcsh% echo $BASH_VERSION

BASH_VERSION: Undefined variable.

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

 

$DIRSTACK

在目录栈中最顶端的值(将会受到pushd和popd的影响)。这个内建变量与dirs命令相符,但是dirs命令会显示目录栈的整个内容。

 

$EDITOR

脚本所调用的默认编辑器,通常情况下是vi或者是emacs。

 

$EUID

有效用户ID。不管当前用户被假定成什么用户,这个数都用来表示当前用户的标识号,也可能使用su命令来达到假定的目的。

$EUID并不一定与$UID相同。

 

$FUNCNAME

当前函数的名字。

xyz23 (){

    echo "$FUNCNAME now executing."  # 打印: xyz23 now executing.

}

 

$GLOBIGNORE

一个文件名的模式匹配列表,如果在通配中匹配到的文件包含有这个列表中的某个文件,那么这个文件将被从匹配到的结果中去掉。

 

$GROUPS

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

root# echo $GROUPS

0

root# echo ${GROUPS[1]}

1

root# echo ${GROUPS[5]}

6

 

$HOME

用户的home目录。

$HOSTNAME

hostname放在一个初始化脚本中,在系统启动的时候分配一个系统名字。然而,gethostname()函数可以用来设置这个Bash内部变量$HOSTNAME。

$ hostname

localhost

$ cat /etc/sysconfig/network

NETWORKING=yes

NETWORKING_IPV6=no

HOSTNAME=localhost

 

$HOSTTYPE

主机类型,就像$MACHTYPE,用来识别系统硬件。

bash$ echo $HOSTTYPE

x86_64

 

$IFS

内部域分隔符,这个变量用来决定Bash在解释字符串时如何识别域或者单词边界。

$IFS默认为空白(空格、制表符和换行符),但这是可以修改的,比如,在分析逗号分隔的数据文件时,就可以设置为逗号。注意,$*使用的是保存在$IFS中的第一个字符。

bash$ echo $IFS | cat -vte

$

bash$ bash -c 'set w x y z;echo "$*"'

w x y z

bash$ bash -c 'set w x y z; IFS=":-;"; echo "$*"'

w:x:y:z

#从字符串中读取命令,并分配参数给位置参数

$IFS处理其他字符与处理空白字符不同。

output_args_one_per_line(){

    for arg

        do echo "[$arg]"

    done

}

IFS=" "

#空白做分隔符

var=" a  b c   "

output_args_one_per_line $var

#[a]

#[b]

#[c]

 

IFS=:

#:做分隔符

var=":a::b:c:::"

output_args_one_per_line $var

#[]

#[a]

#[]

#[b]

#[c]

#[]

#[]

上面,同样的事情也会发生在awk的”FS”域中。

 

$IGNOREEOF

忽略EOF:告诉shell在log out之前要忽略多少文件结束符(control-D)。

 

$LC_COLLATE

常在.bashrc或/etc/profile中设置,这个变量用来控制文件名扩展和模式匹配的展开顺序。如果$LC_COLLATE设置得不正确的话,LC_COLLATE会在文件名匹配中产生不可预料的结果。

 

$LC_CTYPE

这个内部变量用来控制通配和模式匹配中的字符串解释。

 

$LINENO

这个变量用来记录自身在脚本中所在的行号。这个变量只有在脚本使用这个变量的时候才有意义,并且这个变量一般用于调试目的。

# *** 调试代码块开始 ***

last_cmd_arg=$_  # Save it.

echo "At line number $LINENO, variable \"v1\" = $v1"

echo "Last command argument processed = $last_cmd_arg"

# *** 调试代码块结束 ***

 

$MACHTYPE

机器类型,标识系统的硬件。

bash$ echo $MACHTYPE

x86_64-redhat-linux-gnu

 

$OLDPWD

之前的工作目录。

 

$OSTYPE

操作系统类型。

bash$ echo $OSTYPE

linux

 

$PATH

可执行文件的搜索路径,一般为/usr/bin/, /usr/X11R6/bin/, /usr/local/bin等等。

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

echo $PATH

/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin://usr/java/latest/bin:/root/bin

当前的工作目录,通常是不会出现在$PATH中的,这样做的目的是出于安全的考虑。

 

$PIPESTATUS

这个数组变量将保存最后一个运行的前台管道的退出状态码。相当有趣的是,这个退出状态码和最后一个命令运行的退出状态码并不一定相同。

bash$ echo $PIPESTATUS

0

bash$ ls -al | bogus_command

-bash: bogus_command: command not found

bash$ echo $PIPESTATUS

141

bash$ ls -al | bogus_command

-bash: bogus_command: command not found

bash$ echo $?

127

$PIPESTATUS数组的每个成员都保存了运行在管道中的相应命令的退出状态码。$PIPESTATUS[0]保存管道中第一个命令的退出状态码,$PIPESTATUS[1]保存第二个命令的退出状态码,依此类推。

bash$ who | grep nobody | sort

bash$ echo ${PIPESTATUS[*]}

0 1 0

在某些上下文中,变量$PIPESTATUS可能不会给出期望的结果。

bash$ $ ls | bogus_command | wc

bash: bogus_command: command not found

 0       0       0

bash$ echo ${PIPESTATUS[@]}

141 127 0

上边输出不正确的原因归咎于ls的行为。因为如果把ls的结果放到管道上,并且这个输出并没有被读取,那么SIGPIPE将会杀掉它,同时退出状态码变为141,而不是我们所期望的0。这种情况也会发生在tr命令中。

 

$PPID

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

$PROMPT_COMMAND

这个变量保存了在主提示符$PS1显示之前需要执行的命令。

 

$PS1

这是主提示符,可以在命令行中见到它。

 

$PS2

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

 

$PS3

第三提示符,它在一个select循环中显示。

#!/bin/bash

PS3='Choose your favorite vegetable: ' # 设置提示符字串.

select vegetable in "beans" "carrots" "potatoes" "onions" "rutabagas"

do

    echo "Your favorite veggie is $vegetable."

    echo "Yuck!"

    break  # 如果这里没有 'break' 会发生什么?

done

exit 0

 

$PS4

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

 

$PWD

工作目录,你当前所在的目录。

 

$REPLY

当没有参数变量提供给read命令的时候,这个变量会作为默认变量提供给read命令,也可以用于select菜单,但是只提供所选择变量的编号,而不是变量本身的值。

#!/bin/bash

# reply.sh

# REPLY是提供给'read'命令的默认变量.

echo -n "What is your favorite vegetable? "

read

echo "Your favorite vegetable is $REPLY."

#  当且仅当没有变量提供给"read"命令时,REPLY才保存最后一个"read"命令读入的值

echo -n "What is your favorite fruit? "

read fruit

echo "Your favorite fruit is $fruit."

echo "but..."

echo "Value of \$REPLY is still $REPLY."

#  $REPLY还是保存着上一个read命令的值,因为变量$fruit被传入到了这个新的"read"命令中

exit 0

 

$SECONDS

这个脚本已经运行的时间(以秒为单位)。

#!/bin/bash

TIME_LIMIT=10

INTERVAL=1

echo "Hit Control-C to exit before $TIME_LIMIT seconds."

while [ "$SECONDS" -le "$TIME_LIMIT" ]

do

    if [ "$SECONDS" -eq 1 ]

    then

        units=second

    else 

        units=seconds

    fi

    echo "This script has been running $SECONDS $units."

    #  在一台比较慢或者是附载过大的机器上,

    #+ 在单次循环中, 脚本可能会忽略计数.

    sleep $INTERVAL

done

echo -e "\a"  # Beep!(哔哔声!)

exit 0

 

$SHELLOPTS

shell中已经激活的选项的列表,这是一个只读变量。

bash$ echo $SHELLOPTS

braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor

 

$SHLVL

Shell级别,就是Bash被嵌套的深度。如果是在命令行中,那么$SHLVL为1,如果在脚本中那么$SHLVL为2。

 

$TMOUT

如果$TMOUT环境变量被设置为非零值time的话,那么经过time秒后,shell提示符将会超时,这将会导致登出(logout)。

在2.05b版本的Bash中, $TMOUT变量与命令read可以在脚本中结合使用.

# 只能够在Bash脚本中使用, 必须使用2.05b或之后版本的Bash.

TMOUT=3    # 提示输入时间为3秒.

echo "What is your favorite song?"

echo "Quickly now, you only have $TMOUT seconds to answer!"

read song

if [ -z "$song" ]

then

    song="(no answer)"

    # 默认响应.

fi

 

echo "Your favorite song is $song."

有更加复杂的办法可以在脚本中实现定时输入。一种办法就是建立一个定式循环,当超时的时候给脚本发个信号。不过这也需要有一个信号处理例程能够捕捉由定时循环所产生的中断。

定时输入的例子:

#!/bin/bash

# timed-input.sh

TIMELIMIT=3  # 这个例子中设置的是3秒. 也可以设置为其他的时间值.

PrintAnswer(){

    if [ "$answer" = TIMEOUT ]

    then

        echo $answer

    else       # 别和上边的例子弄混了.

        echo "Your favorite veggie is $answer"

        kill $!  # 不再需要后台运行的TimerOn函数了, kill了吧.

              # $! 变量是上一个在后台运行的作业的PID.

    fi

TimerOn()

{

    sleep $TIMELIMIT && kill -s 14 $$ &

     # 等待3秒, 然后给脚本发送一个信号.

Int14Vector()

{

    answer="TIMEOUT"

    PrintAnswer

    exit 14

trap Int14Vector 14   # 定时中断(14)会暗中给定时间限制.

echo "What is your favorite vegetable "

TimerOn

read answer

PrintAnswer

#  无可否认, 这是一个定时输入的复杂实现,

 #+ 然而"read"命令的"-t"选项可以简化这个任务.

#  参考后边的"t-out.sh".

#  如果你需要一个真正优雅的写法...

#+ 建议你使用C或C++来重写这个应用,

 #+ 你可以使用合适的函数库, 比如'alarm'和'setitimer'来完成这个任务.

exit 0

另一种选择是使用stty。

可能最简单的办法就是使用-t选项来read了。

#!/bin/bash

# t-out.sh

TIMELIMIT=4         # 4秒

read -t $TIMELIMIT variable <&1

#                           ^^^

#  在这个例子中,对于Bash 1.x和2.x就需要"<&1"了,但是Bash 3.x就不需要.

if [ -z "$variable" ]  # 值为null?

then

    echo "Timed out, variable still unset."

else 

    echo "variable = $variable"

fi 

exit 0

 

$UID

用户ID号,当前用户的用户标识号,记录在/etc/passwd文件中。

这是当前用户的真实id,即使只是通过使用su命令来临时改变为另一个用户标识,这个id也不会被改变。$UID是一个只读变量,不能在命令行或者脚本中修改它,并且和id内建命令很相像。

变量$ENV、$LOGNAME、$MAIL、$TERM、$USER和$USERNAME都不是Bash的内建变量。然而这些变量经常在Bash的启动文件中被当作环境变量来设置。$SHELL是用户登陆shell的名字,它可以在/etc/passwd中设置,或者也可以在”init”脚本中设置,并且它也不是Bash内建的。

位置参数

$0, $1, $2

位置参数,从命令行传递到脚本,或者传递给函数,或者set给变量。

$#

命令行参数或者位置参数的个数。

$*

所有的位置参数都被看作为一个单词。$*必须被引用起来。

$@

与$*相同,但是每个参数都是一个独立的引用字符串,这就意味着,参数是被完整传递的,并没有被解释或扩展。这也意味着,参数列表中每个参数都被看作为单独的单词。当然,$@应该被引用起来。

#!/bin/bash

# arglist.sh

# 多使用几个参数来调用这个脚本,比如"one two three"

E_BADARGS=65

if [ ! -n "$1" ]

then

    echo "Usage: `basename $0` argument1 argument2 etc."

    exit $E_BADARGS

fi

echo

index=1

echo "Listing args with \"\$*\":"

for arg in "$*"  # 如果"$*"不被""引用,那么将不能正常地工作

do

    echo "Arg #$index = $arg"

    let "index+=1"

done

# $* 将所有的参数看成一个单词

echo

index=1   

echo "Listing args with \"\$@\":"

for arg in "$@"  # 如果"$*"不被""引用,那么将不能正常地工作

do

    echo "Arg #$index = $arg"

    let "index+=1"

done

# $@ 把每个参数都看成是单独的单词

echo

index=1

echo "Listing args with \$*:"

for arg in $*

do

    echo "Arg #$index = $arg"

    let "index+=1"

done

# 未引用的$*将会把参数看成单独的单词

exit 0

shift命令执行以后, $@将会保存命令行中剩余的参数, 但是没有之前的$1, 因为被丢弃了.

#!/bin/bash

# 使用 ./scriptname 1 2 3 4 5 来调用这个脚本

echo "$@"    # 1 2 3 4 5

shift

echo "$@"    # 2 3 4 5

shift

echo "$@"    # 3 4 5

# 每次"shift"都会丢弃$1.

# "$@" 将包含剩下的参数.

$@也可以作为工具使用,用来过滤传递给脚本的输入。cat "$@"结构既可以接受从stdin传递给脚本的输入,也可以接受从参数中指定的文件中传递给脚本的输入。

#!/bin/bash

# rot13.sh: 典型的rot13算法

# 用法: ./rot13.sh filename

# 或     ./rot13.sh <filename

# 或     ./rot13.sh and supply keyboard input (stdin)

cat "$@" | tr 'a-zA-Z' 'n-za-mN-ZA-M'   # "a"变为"n","b"变为"o",等等

#  'cat "$@"'结构允许从stdin或者从文件中获得输入.

exit 0

$*和$@中的参数有时候会表现出不一致而且令人迷惑的行为,这都依赖于$IFS的设置。

#!/bin/bash

#  内部Bash变量"$*"和"$@"的古怪行为,

#+ 都依赖于它们是否被双引号引用起来.

#  单词拆分与换行的不一致的处理.

set -- "First one" "second" "third:one" "" "Fifth: :one"

# 设置这个脚本的参数, $1, $2, 等等

echo 'IFS unchanged, using "$*"'

c=0

for i in "$*"               # 引用起来

do

    echo "$((c+=1)): [$i]"   # 这行在下边每个例子中都一样

done

echo ---

echo 'IFS unchanged, using $*'

c=0

for i in $*               # 未引用

do

    echo "$((c+=1)): [$i]"  

done

echo ---

echo 'IFS unchanged, using "$@"'

c=0

for i in "$@"              

do

    echo "$((c+=1)): [$i]"  

done

echo ---

echo 'IFS unchanged, using $@'

c=0

for i in $@            

do

    echo "$((c+=1)): [$i]"  

done

echo ---

IFS=:

echo 'IFS=":", using "$*"'

c=0

for i in "$*"              

do

    echo "$((c+=1)): [$i]"  

done

echo ---

echo 'IFS=":", using $*'

c=0

for i in $*             

do

    echo "$((c+=1)): [$i]"  

done

echo ---

var=$*

echo 'IFS=":", using "$var" (var=$*)'

c=0

for i in "$var"

do

    echo "$((c+=1)): [$i]"

done

echo ---

echo 'IFS=":", using $var (var=$*)'

c=0

for i in $var

do echo "$((c+=1)): [$i]"

done

echo ---

var="$*"

echo 'IFS=":", using $var (var="$*")'

c=0

for i in $var

do echo "$((c+=1)): [$i]"

done

echo ---

echo 'IFS=":", using "$var" (var="$*")'

c=0

for i in "$var"

do echo "$((c+=1)): [$i]"

done

echo ---

echo 'IFS=":", using "$@"'

c=0

for i in "$@"

do echo "$((c+=1)): [$i]"

done

echo ---

echo 'IFS=":", using $@'

c=0

for i in $@

do echo "$((c+=1)): [$i]"

done

echo ---

 

var=$@

echo 'IFS=":", using $var (var=$@)'

c=0

for i in $var

do echo "$((c+=1)): [$i]"

done

echo ---

 

echo 'IFS=":", using "$var" (var=$@)'

c=0

for i in "$var"

do echo "$((c+=1)): [$i]"

done

echo ---

var="$@"

echo 'IFS=":", using "$var" (var="$@")'

c=0

for i in "$var"

do echo "$((c+=1)): [$i]"

done

echo ---

echo 'IFS=":", using $var (var="$@")'

c=0

for i in $var

do echo "$((c+=1)): [$i]"

done

echo

# 使用ksh或者zsh -y来试试这个脚本.

exit 0

$@与$*中的参数只有在被双引号引用起来的时候才会不同。

当$IFS值为空时, $*和$@的行为依赖于正在运行的Bash或者sh的版本。

#!/bin/bash

#  如果$IFS被设置,但其值为空,那么"$*"和"$@"将不会像期望的那样显示位置参数.

mecho ()       # 打印位置参数

{

    echo "$1,$2,$3";

}

IFS=""         # 设置了,但值为空

set a b c      # 位置参数

mecho "$*"     # abc,,

mecho $*       # a,b,c

mecho $@       # a,b,c

mecho "$@"     # a,b,c

 

其他的特殊参数

$-

传递给脚本的标记(使用set命令)。

 

$!

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

sleep ${TIMEOUT}; eval 'kill -9 $!' &> /dev/null;

 

$_

这个变量保存之前执行的命令的最后一个参数的值。

#!/bin/bash

echo $_      # /bin/bash

                    # 只是调用/bin/bash来运行这个脚本

du >/dev/null        # 这么做命令行上将没有输出

echo $_              # du

ls -al >/dev/null    # 这么做命令行上将没有输出.

echo $_              # -al  (这是最后的参数)

:

echo $_              # :

 

$?

命令、函数或者是脚本本身的退出状态码。

 

$$

脚本自身的进程ID。$$变量在脚本中经常用来构造”唯一的”临时文件名。这么做通常比调用mktemp命令来的简单。

#!/bin/bash

# temp.sh

mktemp

TMPFILE=/tmp/ftp.$$

echo $TMPFILE

exit 0

运行脚本,会输出结果:

/tmp/tmp.lrRiA13050

/tmp/ftp.13049

 

■Shell替换

Shell变量替换,命令替换,转义字符

如果表达式中包含特殊字符,Shell 将会进行替换。例如,在双引号中使用变量就是一种替换,转义字符也是一种替换。

 

echo [-neE][打印内容]

该指令可以将用户指定的打印内容发送到标准输出设备上进行显示。

参    数

功    能

[打印内容]

用户将要输出显示的内容

-e

激活转义字符

 

    下面的转义字符都可以用在 echo 中:

转义字符

含义

\\

反斜杠

\a

警报,响铃

\b

退格(删除键)

\f

换页(FF),将当前位置移到下页开头

\n

换行

\r

回车

\t

水平制表符(tab键) 

\v

垂直制表符

可以使用 echo 命令的 -E 选项禁止转义,默认也是不转义的;使用 -n 选项可以禁止插入换行符。

 

    命令替换

命令替换是指Shell可以先执行命令,将输出结果暂时保存,在适当的地方输出。

 

命令替换的语法:

`command`

注意是反引号,不是单引号

 

下面的例子中,将命令执行结果保存在变量中:

#!/bin/bash

DATE=`date`

echo "Date is $DATE"

USERS=`who | wc -l`

echo "Logged in user are $USERS"

UP=`date ; uptime`

echo "Uptime is $UP"

运行结果:

Date is Thu Jul  2 03:59:57 MST 2009

Logged in user are 1

Uptime is Thu Jul  2 03:59:57 MST 2009

03:59:57 up 20 days, 14:03,  1 user,  load avg: 0.13, 0.07, 0.15

 

$(command)等同于`command`

BASEDIR=$(cd $(dirname $0);pwd)

 

变量替换

变量替换可以根据变量的状态(是否为空、是否定义等)来改变它的值

 

可以使用的变量替换形式:

形式

说明

${var}

变量本来的值

${var:-word}

如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var 的值。

${var:=word}

如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。

${var:?message}

如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。

 

若此替换出现在Shell脚本中,那么脚本将停止运行。

${var:+word}

如果变量 var 被定义,那么返回 word,但不改变 var 的值。

 

 

请看下面的例子:

#!/bin/bash

 

echo ${var:-"Variable is not set"}

echo "1 - Value of var is ${var}"

 

echo ${var:="Variable is not set"}

echo "2 - Value of var is ${var}"

 

unset var

echo ${var:+"This is default value"}

echo "3 - Value of var is $var"

 

var="Prefix"

echo ${var:+"This is default value"}

echo "4 - Value of var is $var"

 

echo ${var:?"Print this message"}

echo "5 - Value of var is ${var}"

运行结果:

 

Variable is not set

1 - Value of var is

Variable is not set

2 - Value of var is Variable is not set

3 - Value of var is

This is default value

4 - Value of var is Prefix

Prefix

5 - Value of var is Prefix

 

■Shell运算符

Shell算数运算符、关系运算符、布尔运算符、字符串运算符等

Bash 支持很多运算符,包括算数运算符、关系运算符、布尔运算符、字符串运算符和文件测试运算符。

    原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。

 

expr 是一款表达式计算工具,使用它能完成表达式的求值操作。

    例如,两个数相加:

    #!/bin/bash

    val=`expr 2 + 2`

    echo "Total value : $val"

 

    算术运算符列表

    运算符    说明    举例

    +    加法    `expr $a + $b` 结果为 30。

    -    减法    `expr $a - $b` 结果为 10。

    *    乘法    `expr $a \* $b` 结果为  200。

    /    除法    `expr $b / $a` 结果为 2。

    %    取余    `expr $b % $a` 结果为 0。

    =    赋值    a=$b 将把变量 b 的值赋给 a。

    ==    相等。用于比较两个数字,相同则返回 true。    [ $a == $b ] 返回 false。

    !=    不相等。用于比较两个数字,不相同则返回 true。    [ $a != $b ] 返回 true。

    注意:条件表达式要放在方括号之间,并且要有空格,例如 [$a==$b] 是错误的,必须写成 [ $a == $b ]。

 

关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值是数字。

 

关系运算符列表

    运算符    说明    举例

    -eq    检测两个数是否相等,相等返回 true。    [ $a -eq $b ] 返回 true。

    -ne    检测两个数是否相等,不相等返回 true。    [ $a -ne $b ] 返回 true。

    -gt    检测左边的数是否大于右边的,如果是,则返回 true。    [ $a -gt $b ] 返回 false。

    -lt    检测左边的数是否小于右边的,如果是,则返回 true。    [ $a -lt $b ] 返回 true。

    -ge    检测左边的数是否大等于右边的,如果是,则返回 true。    [ $a -ge $b ] 返回 false。

    -le    检测左边的数是否小于等于右边的,如果是,则返回 true。    [ $a -le $b ] 返回 true。

    布尔运算符

布尔运算符列表

运算符    说明       举例

!             非运算,表达式为 true 则返回 false,否则返回 true。          [ ! false ] 返回 true。

-o           或运算,有一个表达式为 true 则返回 true。             [ $a -lt 20 -o $b -gt 100 ] 返回 true。

-a           与运算,两个表达式都为 true 才返回 true。             [ $a -lt 20 -a $b -gt 100 ] 返回 false。

 

字符串运算符列表

    运算符    说明    举例

    =    检测两个字符串是否相等,相等返回 true。    [ $a = $b ] 返回 false。

    !=    检测两个字符串是否相等,不相等返回 true。    [ $a != $b ] 返回 true。

    -z    检测字符串长度是否字为0,为0返回 true。    [ -z $a ] 返回 false。

    -n    检测字符串长度是否为0,不为0返回 true。    [ -z $a ] 返回 true。

    str    检测字符串是否为空,不为空返回 true。    [ $a ] 返回 true。

 

文件测试运算符列表

    操作符    说明    举例

    -b file    检测文件是否是块设备文件,如果是,则返回 true。    [ -b $file ] 返回 false。

    -c file    检测文件是否是字符设备文件,如果是,则返回 true。    [ -b $file ] 返回 false。

    -d file    检测文件是否是目录,如果是,则返回 true。    [ -d $file ] 返回 false。

    -f file    检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。    [ -f $file ] 返回 true。

    -g file    检测文件是否设置了 SGID 位,如果是,则返回 true。    [ -g $file ] 返回 false。

    -k file    检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。    [ -k $file ] 返回 false。

    -p file    检测文件是否是具名管道,如果是,则返回 true。    [ -p $file ] 返回 false。

    -u file    检测文件是否设置了 SUID 位,如果是,则返回 true。    [ -u $file ] 返回 false。

    -r file    检测文件是否可读,如果是,则返回 true。    [ -r $file ] 返回 true。

    -w file    检测文件是否可写,如果是,则返回 true。    [ -w $file ] 返回 true。

    -x file    检测文件是否可执行,如果是,则返回 true。    [ -x $file ] 返回 true。

    -s file    检测文件是否为空(文件大小是否大于0),不为空返回 true。    [ -s $file ] 返回 true。

    -e file    检测文件(包括目录)是否存在,如果是,则返回 true。    [ -e $file ] 返回 true。

© 著作权归作者所有

上一篇: Shell语句
下一篇: Shell概述
如比如比
粉丝 126
博文 178
码字总数 286951
作品 0
日本
程序员
私信 提问
Python爬虫Scrapy(三)_Scrapy Shell

本篇将介绍使用scrapy的命令,更多内容请参考:Python学习指南 Scrapy Shell Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查...

小七奇奇
2017/12/26
0
0
Oozie分布式任务的工作流——脚本篇

继前一篇大体上翻译了Email的Action配置,本篇继续看一下Shell的相关配置。 Shell Action Shell Action可以执行Shell脚本命令,工作流会等到shell完全执行完毕后退出,再执行下一个节点。为了...

青夜之衫
2017/12/04
0
0
shell基础知识

Shell脚本是含有若干UNIX命令或可执行程序的文本文件。 1 运行Shell脚本 Shell脚本有两种运行方式,第一种方式是利用sh命令,把shell脚本文件名作为参数。这种执行方式要求shell脚本文件具有...

长平狐
2013/01/06
82
0
shell基础知识

Shell脚本是含有若干UNIX命令或可执行程序的文本文件。 1 运行Shell脚本 Shell脚本有两种运行方式,第一种方式是利用sh命令,把shell脚本文件名作为参数。这种执行方式要求shell脚本文件具有...

晨曦之光
2012/03/02
286
0
17个案例带你3分钟搞定Linux正则表达式

正则表达式是一种字符模式,用于在查找过程中匹配制定的字符。 元字符通常在Linux中分为两类: Shell元字符,由Linux Shell进行解析; 正则表达式元字符,由vi/grep/sed/awk等文本处理工具进...

Mr_zebra
2018/09/30
22
0

没有更多内容

加载失败,请刷新页面

加载更多

PostgreSQL 11.3 locking

rudi
今天
5
0
Mybatis Plus sql注入器

一、继承AbstractMethod /** * @author beth * @data 2019-10-23 20:39 */public class DeleteAllMethod extends AbstractMethod { @Override public MappedStatement injectMap......

一个yuanbeth
今天
11
1
一次写shell脚本的经历记录——特殊字符惹的祸

本文首发于微信公众号“我的小碗汤”,扫码文末二维码即可关注,欢迎一起交流! redis在容器化的过程中,涉及到纵向扩pod实例cpu、内存以及redis实例的maxmemory值,statefulset管理的pod需要...

码农实战
今天
4
0
为什么阿里巴巴Java开发手册中不建议在循环体中使用+进行字符串拼接?

之前在阅读《阿里巴巴Java开发手册》时,发现有一条是关于循环体中字符串拼接的建议,具体内容如下: 那么我们首先来用例子来看看在循环体中用 + 或者用 StringBuilder 进行字符串拼接的效率...

武培轩
今天
9
0
队列-链式(c/c++实现)

队列是在线性表功能稍作修改形成的,在生活中排队是不能插队的吧,先排队先得到对待,慢来得排在最后面,这样来就形成了”先进先出“的队列。作用就是通过伟大的程序员来实现算法解决现实生活...

白客C
今天
81
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部