Sh

Sh。~~~shell echo “hello world!”

sh 脚本

变量

打印

1
2
3
4
5
# 打印
echo “hello world!”

# shell默认是不转义上面的字符的。需要加-e选项。带上双引号
echo -e "a is $a \n"

变量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 定义变量
variable_name=1
readonly variable_name_2=2	# 不可变变量

# 打印变量
echo $variable_name
echo ${variable_name}		# 建议加上花括号

# 删除变量
unset variable_name
变量 含义
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2
$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。被双引号(" “)包含时,与 $* 稍有不同
$? 上个命令的退出状态,或函数的返回值。一般情况下,大部分命令执行成功会返回 0,失败返回 1
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
形式 说明
${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 的值。

shell示例

下面的脚本用于php安装过程中安装zip扩展。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
php_zip_ins.sh
#!/bin/bash
#zip install

if [ -d php-5.4.25/ext/zip ];then
	cd php-5.4.25/ext/zip
else
	tar zxvf php-5.4.25.tar.gz
	cd php-5.4.25/ext/zip
fi
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make
[ $? != 0 ] && exit
make install
echo 
grep 'no-debug-zts-20100525' /usr/local/php/etc/php.ini
if [ $? != 0 ];then
        echo '' >> /usr/local/php/etc/php.ini
        echo 'extension_dir=/usr/local/php/lib/php/extensions/no-debug-zts-20100525' >> /usr/local/php/etc/php.ini
fi
grep 'zip.so' /usr/local/php/etc/php.ini
if [ $? != 0 ];then
	echo 'extension=zip.so' >> /usr/local/php/etc/php.ini
fi
echo "zip install is OK"


/usr/local/apache2/bin/apachectl restart
cd -
rm -rf php-5.4.25
echo "all ok!"
ls /usr/local/php/lib/php/extensions/no-debug-zts-20100525/

运算

数学运算

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 命令行直接计算
expr 2 + 2   #4
expr 3 - 2   #1
expr 3 / 2   #1
expr 3 \* 2   #6

# 使用表达式
a=10
b=20
val=`expr $a + $b`
echo "a + b : $val"

关系运算

1
2
3
4
5
6
7
8
9
#!/bin/sh
a=10
b=20
if [ $a -eq $b ]
then
   echo "$a -eq $b : a is equal to b"
else
   echo "$a -eq $b: a is not equal to b"
fi
运算符 说明
=-eq 检测两个数是否相等,相等返回 true。同算数运算符==
=-ne 检测两个数是否相等,不相等返回 true
=-gt 检测左边的数是否大于右边的,如果是,则返回 true。
=-lt 检测左边的数是否小于右边的,如果是,则返回 true。
=-ge 检测左边的数是否大等于右边的,如果是,则返回 true。
=-le 检测左边的数是否小于等于右边的,如果是,则返回 true。

布尔运算

1
2
3
4
if [ 3 -eq 3 -a 3 -lt 5 ]
then
    echo 'ok'
fi;
运算符 说明
! 非运算,表达式为 true 则返回 false,否则返回 true。
-o 或运算(or),有一个表达式为 true 则返回 true。
-a 与运算(and),两个表达式都为 true 才返回 true。

字符串运算

运算符 说明 举例
= 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。
!= 检测两个字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。
-n 检测字符串长度是否为0,不为0返回 true。 [ -n $a ] 返回 true。
str 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。

文件运算

1
2
3
4
5
6
7
8
9
#!/bin/sh
file="/tmp/test.sh"

if [ -e $file ]
then
   echo "File exists"
else
   echo "File does not exist"
fi
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
操作符	说明	举例

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

-c file	检测文件是否是字符设备文件,如果是,则返回 true。	[ -c $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。

字符串和数组

字符串

1
2
3
4
str="hello"
${#str} # 读取字符串长度
echo ${str} # 读取字符串全部
echo ${str:1} # 截取字符串

数组

1
2
3
4
5
6
arr=(a1 a2 a3)
echo ${#arr[*]} # 读取数组长度
echo ${#arr[1]} # 读取数组某个元素长度

echo ${arr[*]} # 读取数组全部
echo ${arr[1]} # 读取数组某个元素

条件判断

if

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash/

a=10
b=20
if [ $a == $b ]
then 
	echo "a is equal to b"
elif [ $a -gt $b ]
then
	echo "a is greater to b"
# 注意 else 后面没有 then
else
	echo "a is less to b"
fi

case

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash/

grade="B"

case $grade in 
	"A") echo "Very Good!";;
	"B") echo "Good!";;
	"C") echo "Come On!";;
	*) 
		echo "You Must Try!"
		echo "Sorry!";;
esac

经典例子(从命令行读取参数)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/sh

usage()
{
    echo "Usage: $0 -s [start|stop|reload|restart] -e [online|test]"
    exit 1
}

if [ -z $1 ]; then
    usage
fi

while getopts 's:e:h' OPT; do
    case $OPT in
        s) cmd="$OPTARG";;
        e) env="$OPTARG";;
        h) usage;;
        ?) usage;;
    esac
done

echo $cmd
echo $env

循环语句

for

1
2
3
4
5
6
#!/bin/bash/

for value in 1 2 3 4 5
do 
	echo "The value is $value"
done

遍历当前目录的文件

1
2
3
4
5
#!/bin/bash
for FILE in *
do
   echo $FILE
done

while

1
2
3
4
5
6
7
8
#!/bin/bash

c=0;
while [ $c -lt 3 ]
do
	echo "Value c is $c"
	c=`expr $c + 1`
done

until

1
2
3
4
5
6
7
8
#!/bin/bash

c=0;
until [ $c -eq 3 ]
do
	echo "Value c is $c"
	c=`expr $c + 1`
done

函数

1
2
3
4
5
6
7
8
# function 为可选
function function_name () {
    list of commands
    [ return value ]
}

# 获取函数返回值到变量
value=$(function_name)

输入输出重定向

输入重定向

1
2
3
4
5
6
# 内容被重定向到文件。
# 如果文件存在,会被覆盖
command > file

# >> 为追加,不会覆盖
command >> file

输出重定向

1
command < file

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

  • 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
  • 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
  • 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。

默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。

1
2
3
4
5
# stderr 重定向到 file
command 2 > file

# stdout 和 stderr 合并后重定向到 file
command > file 2>&1
命令 说明
command > file 将输出重定向到 file。
command < file 将输入重定向到 file。
command > > file 将输出以追加的方式重定向到 file。
n > file 将文件描述符为 n 的文件重定向到 file。
n » file 将文件描述符为 n 的文件以追加的方式重定向到file。
n >& m 将输出文件 m 和 n 合并。
n <& m 将输入文件 m 和 n 合并。
« tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入。

特殊

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 将两个 delimiter 之间的内容(document) 作为输入传递给 command
command << delimiter
    document
delimiter

# 示例:通过 wc -l 命令计算 document 的行数
wc -l << EOF
    This is a simple lookup program
    for good (and bad) restaurants
    in Cape Town.
EOF

/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃

Shell文件包含

被包含文件:sub.sh

1
name="yjc"

主文件:test.sh

1
2
. ./sub.sh
echo $name

运行主文件的结果:

1
yjc

注意

1
2
3
4
5
6
7
8
9
# 获取当前正在执行脚本的绝对路径
basepath=$(cd `dirname $0`; pwd)

# 按特定字符串截取字符串
str=/www/html/php/myapp/
b=($(echo $str|sed 's#/# #g'))
b_len=`expr ${#b[*]} - 1`
app_name=${b[$b_len]}
echo $app_name
Licensed under CC BY-NC-SA 4.0
Gear(夕照)的博客。记录开发、生活,以及一些不足为道的思考……