solaris Shell脚本学习笔记-语法

http://www.cnblogs.com/weixun/p/3262029.html

 

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, 前者不能得到正确结果。

xargs utility [arguments]命令在标准输入上取得参数列表,
再将它们以适当大小(ARG_MAX)组装起来加在utility [arguments]后面.
这在命令行长度超过限制(ARG_MAX)的情况下非常有用.例如,
find /usr/include -type f | xargs grep POSIX_OPEN_MAX /dev/null 
*ARG_MAX可以用getconf ARG_MAX来查看。

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,表示脚本正常终止。

 

 

https://www.cnblogs.com/xunbu7/p/6187017.html

shell中$(( )) 与 $( ) 还有${ }的区别

http://blog.chinaunix.net/uid-14351756-id-2820651.html

$( ) 与 ` ` (反引号)
在 bash shell 中,$( ) 与 ` ` (反引号) 都是用来做命令替换用(command substitution)的。

所谓的命令替换与我们第五章学过的变量替换差不多,都是用来重组命令行:
* 完成引号里的命令行,然后将其结果替换出来,再重组命令行。
例如:
[code]$ echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)[/code]
如此便可方便得到上一星期天的日期了… ^_^

用 $( ) 的理由:

1,   ` ` 很容易与 ' ' ( 单引号)搞混乱,尤其对初学者来说。
有时在一些奇怪的字形显示中,两种符号是一模一样的(直竖两点)。
当然了,有经验的朋友还是一眼就能分辩两者。只是,若能更好的避免混乱,又何乐不为呢? ^_^

2, 在多层次的复合替换中,` ` 须要额外的跳脱( \` )处理,而 $( ) 则比较直观。例如:
这是错的:
[code]command1 `command2 `command3` `[/code]
原本的意图是要在 command2 `command3` 先将 command3 提换出来给 command 2 处理,
然后再将结果传给 command1 `command2 …` 来处理。
然而,真正的结果在命令行中却是分成了 `command2 ` 与 “ 两段。
正确的输入应该如下:
[code]command1 `command2 \`command3\` `[/code]

要不然,换成 $( ) 就没问题了:
[code]command1 $(command2 $(command3))[/code]
只要你喜欢,做多少层的替换都没问题啦~~~   ^_^

$( ) 的不足:
1. ` ` 基本上可用在全部的 unix shell 中使用,若写成 shell script ,其移植性比较高。
而 $( ) 并不见的每一种 shell 都能使用,我只能跟你说,若你用 bash2 的话,肯定没问题…   ^_^

${ } 用来作变量替换。
一般情况下,$var 与 ${var} 并没有啥不一样。
但是用 ${ } 会比较精确的界定变量名称的范围,比方说:
$ A=B
$ echo $AB
原本是打算先将 $A 的结果替换出来,然后再补一个 B 字母于其后,
但在命令行上,真正的结果却是只会提换变量名称为 AB 的值出来…
若使用 ${ } 就没问题了:
$ echo ${A}B
BB

不过,假如你只看到 ${ } 只能用来界定变量名称的话,那你就实在太小看 bash 了﹗
有兴趣的话,你可先参考一下 cu 本版的精华文章:
http://www.chinaunix.net/forum/viewtopic.php?t=201843

为了完整起见,我这里再用一些例子加以说明 ${ } 的一些特异功能:
假设我们定义了一个变量为:
file=/dir1/dir2/dir3/my.file.txt
我们可以用 ${ } 分别替换获得不同的值:
${file#*/}:拿掉第一条 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:拿掉最后一条 / 及其左边的字符串:my.file.txt
${file#*.}:拿掉第一个 .  及其左边的字符串:file.txt
${file##*.}:拿掉最后一个 .  及其左边的字符串:txt
${file%/*}:拿掉最后条 / 及其右边的字符串:/dir1/dir2/dir3
${file%%/*}:拿掉第一条 / 及其右边的字符串:(空值)
${file%.*}:拿掉最后一个 .  及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:拿掉第一个 .  及其右边的字符串:/dir1/dir2/dir3/my
记忆的方法为:
[list]# 是去掉左边(在鉴盘上 # 在 $ 之左边)
% 是去掉右边(在鉴盘上 % 在 $ 之右边)
单一符号是最小匹配﹔两个符号是最大匹配。[/list]
${file:0:5}:提取最左边的 5 个字节:/dir1
${file:5:5}:提取第 5 个字节右边的连续 5 个字节:/dir2

我们也可以对变量值里的字符串作替换:
${file/dir/path}:将第一个 dir 提换为 path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:将全部 dir 提换为 path:/path1/path2/path3/my.file.txt

利用 ${ } 还可针对不同的变量状态赋值(没设定、空值、非空值): 
${file-my.file.txt} :假如 $file 没有设定,则使用 my.file.txt 作传回值。(空值及非空值时不作处理) 
${file:-my.file.txt} :假如 $file 没有设定或为空值,则使用 my.file.txt 作传回值。 (非空值时不作处理)
${file+my.file.txt} :假如 $file 设为空值或非空值,均使用 my.file.txt 作传回值。(没设定时不作处理)
${file:+my.file.txt} :若 $file 为非空值,则使用 my.file.txt 作传回值。 (没设定及空值时不作处理)
${file=my.file.txt} :若 $file 没设定,则使用 my.file.txt 作传回值,同时将 $file 赋值为 my.file.txt 。 (空值及非空值时不作处理)
${file:=my.file.txt} :若 $file 没设定或为空值,则使用 my.file.txt 作传回值,同时将 $file 赋值为 my.file.txt 。 (非空值时不作处理)
${file?my.file.txt} :若 $file 没设定,则将 my.file.txt 输出至 STDERR。 (空值及非空值时不作处理)
${file:?my.file.txt} :若 $file 没设定或为空值,则将 my.file.txt 输出至 STDERR。 (非空值时不作处理)

 

tips:
以上的理解在于, 你一定要分清楚 unset 与 null 及 non-null 这三种赋值状态.
一般而言, : 与 null 有关, 若不带 : 的话, null 不受影响, 若带 : 则连 null 也受影响.

还有哦,${#var} 可计算出变量值的长度:
${#file} 可得到 27 ,因为 /dir1/dir2/dir3/my.file.txt 刚好是 27 个字节…

接下来,再为大家介稍一下 bash 的组数(array)处理方法。
一般而言,A="a b c def" 这样的变量只是将 $A 替换为一个单一的字符串,
但是改为 A=(a b c def) ,则是将 $A 定义为组数…
bash 的组数替换方法可参考如下方法:
${A[@]} 或 ${A[*]} 可得到 a b c def (全部组数)
${A[0]} 可得到 a (第一个组数),${A[1]} 则为第二个组数…
${#A[@]} 或 ${#A[*]} 可得到 4 (全部组数数量)
${#A[0]} 可得到 1 (即第一个组数(a)的长度),${#A[3]} 可得到 3 (第四个组数(def)的长度)
A[3]=xyz 则是将第四个组数重新定义为 xyz …

好了,最后为大家介绍 $(( )) 的用途吧:它是用来作整数运算的。
在 bash 中,$(( )) 的整数运算符号大致有这些:
+ - * / :分别为 "加、减、乘、除"。
% :余数运算
& | ^ !:分别为 "AND、OR、XOR、NOT" 运算。

例:
$ a=5; b=7; c=2
$ echo $(( a+b*c ))
19
$ echo $(( (a+b)/c ))
6
$ echo $(( (a*b)%c))
1

在 $(( )) 中的变量名称,可于其前面加 $ 符号来替换,也可以不用,如:
$(( $a + $b * $c)) 也可得到 19 的结果

此外,$(( )) 还可作不同进位(如二进制、八进位、十六进制)作运算呢,只是,输出结果皆为十进制而已:
echo $((16#2a)) 结果为 42 (16进位转十进制)
以一个实用的例子来看看吧:
假如当前的   umask 是 022 ,那么新建文件的权限即为:
$ umask 022
$ echo "obase=8;$(( 8#666 & (8#777 ^ 8#$(umask)) ))" | bc
644

事实上,单纯用 (( )) 也可重定义变量值,或作 testing:
a=5; ((a++)) 可将 $a 重定义为 6 
a=5; ((a–)) 则为 a=4
a=5; b=7; ((a < b)) 会得到   0 (true) 的返回值。
常见的用于 (( )) 的测试符号有如下这些:
<:小于
>:大于
<=:小于或等于
>=:大于或等于
==:等于
!=:不等于

分类: Linux学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值