您的位置:首页 > 运维架构 > Shell

Shell脚本学习笔记-语法

2010-06-21 22:57 453 查看
Solaris下Shell脚本学习笔记。

Shell语法

Shell中变量都是全局的,如果需要在函数中使用局部变量,在变量前加上local

'expression'单引号括起的表达式中不允许变量扩展;

"expression"双引号中则允许,可以用来连接变量, fullname="$firstname $lastname"

(expression1;expression2;...)括号中的指令形成指令群,也成为subshell,

其中定义的变量作用范围限定于指令群本身,也不会对主脚本的状态产生影响.

例如tar cf - * | ( cd /tmp/; tar -xf -) 执行完毕后当前目录不会改变

((expression)) 和let命令类似用于算术运算

((b=10**2)); echo $b; 等同于let b=10**2; **表示乘方

{} 大括号可用来表示逗号隔开的字符串的组合,

ls ab{c,d}.txt 相当于 ls abc.txt abd.txt;

mkdir {ab,cd}ef{12,34} 相当于mkdir abef12 abef34 cdef12 cdef34

$? 上次执行的shell返回结果

$$ 代表进程ID;

$!最后一个后台命令的进程ID(可供稍后调用wait使用);

$PPID 父进程ID;

$PS1命令提示符,默认为$;

$PS2 行继续提示符,默认为>;

$PS4 用set -x打开跟踪,执行跟踪的提示符,默认为+

$1, $2...${10}... 读取脚本中的参数, 超过9加大括号; $0为指令本身; $#为变量的总数.

$@("$@"="$1" "$2" "$3" ...)或者$*("$*"= "$1 $2 $3 ...")列出所有的参数,

在不加双引号的情况下,两者相同

${VAR-DEFAULT} 或者 ${VAR=DEFAULT} 使用一个默认值来代替那些不存在的变量;

如果变量不存在后者同时会导致VAR被设置为DEFAULT.

${VAR:-DEFAULT} 或者 ${VAR:=DEFAULT} 使用一个默认值来代替那些不存在或者值为空的变量;

如果变量不存在或者为空后者同时会导致VAR被设置为DEFAULT.

${VAR?MSG} 如果变量不存在显示出错误MSG并中止脚本的执行同时返回退出码1,否则返回VAR;

${VAR:?MSG} 如果变量不存在或者为空显示错误MSG并中止脚本的执行同时返回退出码1,否则返回VAR;

${VAR+MSG} 如果变量不存在就会返回null,否则返回MSG;

${VAR:+MSG} 如果变量不存在或者值为空就返回null,否则返回MSG

${#VAR} 变量的长度

${VAR%word} 如果word匹配变量结尾部分,删除匹配的最短部分,然后返回剩余部分

${VAR%%word} 如果word匹配变量结尾部分,删除匹配的最长部分,然后返回剩余部分

${VAR#word} 如果word匹配变量开始部分,删除匹配的最短部分,然后返回剩余部分

${VAR##word} 如果word匹配变量开始部分,删除匹配的最长部分,然后返回剩余部分

$(command) 或者 `command` 返回当前执行命令的结果

$((...)) 对括号内的表达式求值, 例如 x=2; x=$(($x**3)); echo $x

: 不做任何事情,只作参数展开,但是返回值为0. :>file 等同于 cat /dev/null > file;

. 读取文件并执行文件中的内容,注意是在当前shell进程中执行,变量赋值,函数定义,改变目录等影响都是全局的

使用read读取输入时默认行为是把输入行尾的反斜杠\看作续行符, -r选项可以不把\看作续行符.

使用read读取输入时使用$IFS进行字段切分.例如

while IFS=: read user password uid gid fullname homedir shell

do

echo $user $password $uid $gid $fullname $homedir $shell

done < /etc/passwd

*在执行某个命令时临时修改某个变量: PATH=.:/usr/bin test.sh

*输入重定向置于循环体结尾,也可以使用管道 cat /etc/passwd | while ...

*读取密码stty -echo;read pass < /dev/tty;stty echo;

eval命令读取它的参数然后把结果作为command给shell执行,

在变量替换或命令输出作为命令执行的情况下,比较有用.

例如, x="ls | more", 分别执行$x 和eval $x, 前者不能得到正确结果。

command在查找待执行的命令时,避开shell函数; -p 查找命令时,使用$PATH的默认值

shell查找命令的顺序:特殊内建命令->shell函数->一般内建命令->$PATH目录下的外部命令

特殊内建命令有: . break continue eval exec exit export readonly return set shift times trap unset

一般内建命令有: alias bg cd command false fc fg getopts jobs kill newgrp pwd read true umask unalias wait

所以可以用shell函数来覆盖一般内建命令,例如

cd () {

command cd "$@"

x=`pwd`

PS1="${x##*/}\$ "

}

cd - 变更工作目录到上一次工作目录

cd ~或者cd 变更工作目录到当前用户目录

cd ~user变更工作目录到user用户目录

test命令

-e file 是否存在; -d file 是否目录; -f file 是否一般文件; -h file | -L file 是否符号链接;

-s file 是否文件为空

-r file; -w file; -x file 是否可读;是否可写;是否可执行文件或者可被查找的目录

-n string 是否string不为null; -z string 是否string为null;

s1 = s2 字符串相同(注意=符号前后的空格); s1 != s2 字符串不相同

n1 -eq n2; n1 -ne n2; n1 -lt n2; n1 -gt n2; n1 -le n2; n1 -ge n2 整数比较

*前置!表示否定结果; -a 逻辑与; -o 逻辑或

*所有的变量展开都加上"",防止变量本身为空引起的问题,例如 test -f "$FILE"

*[] 中括号用于条件判断符号,可理解为指向test命令的一个软链接,用法可完全参照test.

注意紧挨着括号要有空格,例如 if [ ! -f file ]

if [ ... ]

then

...

elif [ ... ]

then

...

else

...

fi

case $1 in

valueA)

...

;;

valueB | valueC)

...

;;

*)

...

;;

esac

for i [in list]

do

...

done

*in list可选,如果省略等同in "$@", 循环整个参数列表.

*list的写法例: for i in 3 4 5; for i in *.txt; for i in {1..10}; for ((i=1;i<=10;++i))

{ while | until } condition

do

...

done

利用getopts命令处理输入参数.

file= verbose= quiet= long=

while getopts :vqf:l opt

do

case $opt in

v) verbose=true

quiet=

;;

q) quiet=true

verbose=

;;

f) file=$OPTARG

;;

l) long=true

;;

?) echo "$0: invalid option -$OPTARG" >&2

echo "Usage: $0 [-f file] [-vql] [files...]" >&2

exit 1

;;

esac

done

shift $((OPTIND - 1))

*选项后面的:表示该选项必须提供一个参数.getopts会把参数值放到变量OPTARG中.

*OPTIND被设置为下一个待处理参数的索引值.

*:作为选项字符串的第一个字符,会导致针对非法选项

1)不输出错误信息;

2)将变量$opt设置为?并且把非法选项放到变量OPTARG中.

*最后的shift $((OPTIND - 1))删除所有选项.留下参数,可以利用$1,$2...获得.

*注意OPTIND是全局的,如果某个函数也需要调用getopts来解析自己的参数,需要重设OPTIND为1.

<<可以在脚本中提供嵌入输入并可以在嵌入文件中使用变量替换,

cat << EOF

...

$HOME

...

EOF

*如果要避免发生变量替换,可以把定界符用引号括起来,例如 cat << 'EOF'

*使用<<-形式则删除嵌入文本中每一行开始的tab(空格不会删除),这样可以提高shell脚本的可读性

exec命令可以用来进行IO重定向,改变文件描述符,例如

exec 3<file

read arg1 arg2 < &3

再例如,

exec 99>&2 文件描述符99指向标准错误输出

exec 2>/tmp/$0.log 文件描述符2指向文件

...

exec 2>&99 恢复文件描述符2为标准错误输出

exec 99>&- 关闭文件描述符99

set命令

1)不带参数的set打印所有的shell变量

2)+-分别表示关闭/打开特定的shell选项。($- 表示当前已经打开的shell选项)

-a allexport,export所有后续定义的变量

-b notify,立即显示作业完成的信息,而不是等待下一个提示符。

-C noclobber,打开防止覆盖,>重定向遇到目标文件存在就会失败,这种情况下可以使用>|来做重定向。

-e errexit,命令退出值非零则退出shell。

-f noglob,停用通配符展开

-m monitor,打开作业控制(默认是打开的)

-n noexec,读取命令并且检查语法错误但是不执行。在交互式shell下忽略此选项。

-u nounset,视未定义的变量为错误而不是作为null。

-v verbose,在执行命令前打印命令行,不做变量替换。

-x xtrace,在执行命令前打印命令行,做变量替换。另一种方式 bash -x scriptfile。

- 关闭-v -x选项。

trap命令用来捕获信号 trap 'command' signal lis

信号可以用数字也可以用名字,可以使用man signal.h查看对应关系.

除了标准信号trap还提供一个特殊信号EXIT或者0,表示脚本正常终止。

Xargs用法详解

之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了xargs命令,例如:

find /sbin -perm +700 |ls -l 这个命令是错误的

find /sbin -perm +700 |xargs ls -l 这样才是正确的

xargs 可以读入 stdin 的资料,并且以空白字元或断行字元作为分辨,将 stdin 的资料分隔成为 arguments 。 因为是以空白字元作为分隔,所以,如果有一些档名或者是其他意义的名词内含有空白字元的时候, xargs 可能就会误判了

选项解释

-0 当sdtin含有特殊字元时候,将其当成一般字符,比如 /'空格 等

-a file 从文件中读入作为sdtin

-e flag ,注意有的时候可能会是-E,flag必须是一个以空格分隔的标志,当xargs分析到含有flag这个标志的时候就停止。例如

$ cat 0
1
2
3
$ cat 0 | xargs -E '2' echo
1


-p 当每次执行一个argument的时候询问一次用户。

-n num 后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用所有的。例

$ cat 0 | xargs -E '3' -p -n 1 echo
echo 1?...y
1
echo 2?...y
2
-t 表示先打印命令,然后再执行。

-i ,这得看linux支持了,将xargs的每项名称,一般是一行一行赋值给{},可以用{}代替。例如

$ ls
0  1  2
$ ls | xargs -i mv {} {}.bk
$ ls
0.bk  1.bk  2.bk
-I,-i已经是deprecated参数,-I可以指定替换字符串。例如

$ ls | xargs -I x mv x x.bk
$ ls
0.bk.bk  1.bk.bk  2.bk.bk
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: