Shell基本使用

Introduction

Shell是一个用来与linux,unix系统进行交互的的解释型程序。Shell主要有两种使用方式,一种是直接通过shell terminal输入命令进行交互,一种是写好shell脚本程序,然后批量执行脚本里的命令。

第一个shell脚本hello.sh:

1
2
#!/bin/bash
echo "hello, world"

#!指定执行这个脚本的解释器,常用的解释器有sh,bash。为了执行这个程序我们可以在terminal输入:

1
2
chmod 777 hello.sh  # 设置执行权限
./hello.sh

或者:

1
sh hello.sh

sh一般是在系统PATH里的,可以直接在terminal中使用该命令,一般PATH包含在/bin, /sbin, /usr/bin, /user/sbin中,如果需要在terminal中直接使用某个命令,我们需要将其可执行程序加入到这些目录中,或者将该可执行程序的路径加入PATH中。

变量

  • 定义和使用变量

shell不需要声明变量类型,可以直接定义变量或修改变量数据类型,注意定义变量是不要在变量名前$符号。

var="hello, world"

在使用一个定义过的变量时,只需要在变量名前加$符号,比较好的方式是同时对变量名加上花括号。

1
2
echo $var
echo ${var}
  • 在重新定义变量时,直接像第一次定义变量时定义:
1
2
3
4
5
var="hello, world"
echo ${var}

var="hello, chen"
echo ${var}
  • 通过readonly设置只读变量
1
2
var="hello, world"
readonly var
  • 删除变量(不能删除readonly变量)
1
unset var
  • 变量类型

(1)局部变量,当前脚本定义的变量。
(2)环境变量,多个不同shell进程可使用的环境变量。
(3)shell变量,shell有特殊定义的变量。

  • 一些shell变量
变量 含义
$0 当前脚本文件名
$n 传递给脚本的第n个参数
$# 参数个数
$* 所有参数,需要注意的是,所有被””包括的将作为单个参数
$@ 所有参数,需要注意的是,被””包括的多个元素将作为各个不同参数
$? 上个命令的退出状态,或函数的返回值。
$$$$ 当前shell进程ID

Shell替换

  • 变量和字符替换

字符串中如果包含特殊字符或者变量,shell将会替换这些符号或变量,注意替换转义字符需要加上-e参数。

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

var="chen"

echo -e "hello, $var \n"
echo "hello, $var \n"
1
2
hello, chen
hello, chen \n
  • 命令替换
1
2
3
processInfo=`ps` # `,not '
# `commannd`
echo -e "processes: \n $processInfo"

Shell运算

使用expr表达式

1
2
3
4
5
6
7
var=`expr 1+0`
echo "result: $var"

a=1
b=1
var=`expr $a + $b`
echo "result: $var"
  • 算术运算符
operator example expression
+ `expr $a + $b `
- `expr $a - $b `
* `expr $a * $b `
/ `expr $a / $b `
% `expr $a % $b `
= a=$b
== [$a == $b]
!= [$a != $b]
  • 关系运算符
operator example expression
-eq [$a -eq $b]
-ne [$a -ne $b]
-gt [$a -gt $b]
-lt [$a -lt $b]
-ge [$a -ge $b]
-le [$a -le $b]
  • 逻辑运算符
operator example expression
! [! false]
-o [$a -lt 20 -o $b -gt 100 ]
-a [$a -lt 20 -a $b -gt 100 ]
  • 字符串运算符
operator example expression
= [ $a = $b ]
!= [ $a != $b ]
-z 长度是否为0, 为0则返回true,[-z $a]
str 字符串是否为空,不为空位返回true, [$a]
  • 文件测试运算符
expression meaning
是块设备文件? [ -b $file ]
是字符设备文件? [ -c $file ]
是目录? [ -d $file ]
是普通文件? [ -f $file ]
是否可读 [ -r $file ]
是否可写 [ -w $file ]
是否可执行 [ -x $file ]
是否为空(文件大小是否大于0) [ -s $file ]
文件(包括目录)是否存在 [ -e $file ]

字符串

单引号字符串,内容不会被修改。
双引号字符串,字符串中可以出现变量和转义字符。

1
2
3
4
5
6
7
var="chen"
echo ${#var} #获取字符串长度
echo ${var:1:3} #获取字字符串
echo `expr index "$var" he`

printf "%d %s\n" 1 "abc"
printf %s abc def # 可以没有引号,可以超出参数(重复调用)

数组

  • 定义数组
1
2
3
4
first_array=(value0 value1 ...) #元素用空格分开

second_array[0]=value0 # 第二种方式定义
second_array[1]=value1
  • 操作数组
1
2
3
4
5
6
7
8
9
10
${array_name[index]} # 一般格式
value=${array_name[2]}

${array_name[*]} # 获取所有元素
${array_name[@]} # 获取所有元素

length=${#array_name[@]} # 获取数组元素个数
length=${#array_name[*]} # 获取数组元素个数

length=${#array_name[n]} # 获取数组当个元素长度

if else

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if[ expression ]
then
...
fi

if [ expression ]
then
...
else
...
fi

if [ expression ]
then
...
elif [ expression ]
then
...
elif test expression # test 命令用于检查某个条件是否成立,与方括号([ ])类似。
...
else
...
fi

case esac

1
2
3
4
5
6
7
8
9
10
11
case $var in
mode1)
...
;;
mode2)
...
;;
*)
...
;;
esac

for

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
for varible in list do
...
done

\# 列表是一组值(数字、字符串等)组成的序列,每个值通过空格分隔。每循环一次,就将列表中的下一个值赋给变量。

for i in 1 2 3
do
echo "value: $i"
done

for char in "this"
do
echo $char
done


for file in $HOME/.bash*
do
echo $file
done

while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
COUNTER=0
while [ $COUNTER -lt 5 ]
do
COUNTER='expr $COUNTER+1'
echo $COUNTER
done

\# while循环可用于读取键盘信息。下面的例子中,输入信息被设置为变量FILM,按<Ctrl-D>结束循环。

echo 'type <CTRL-D> to terminate'
echo -n 'enter your most liked film: '
while read FILM
do
echo "Yeah! great film the $FILM"
done

break, continue

1
2
3
4
break
break n
continue
continue n

function

  • 定义
1
2
3
4
5
6
7
8
function_name () {
list of commands
[ return value ]
}

function_name # 执行函数,不需要括号

unset function_name

Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
funWithParam(){
echo "The value of the first parameter is $1 !"
echo "The value of the second parameter is $2 !"
echo "The value of the tenth parameter is $10 !"
echo "The value of the tenth parameter is ${10} !"
echo "The value of the eleventh parameter is ${11} !"
echo "The amount of the parameters is $# !" # 参数个数
echo "The string of the parameters is $* !" # 传递给函数的所有参数
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数…注意,$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。

dict

1
2
3
4
5
6
7
8
9
10
11
12
13
14
declare -A dict
mkdir res

dic=([65222]=2 [14280907]=3 [15817900]=2 [16966544]=3)

for session_id in ${!dic[*]}
do
echo ${dic[$session_id]}
for((i=1;i<=${dic[$session_id]};i++))
do
java -cp "./bin:./lib/*" testProgram $session_id $i 1 cla gm
done
mv logs res/$session_id
done

Shell输入输出重定向

文件包含

参考Shell教程Linux教程

example

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/bin/bash

start=$(date +%s)

i=0
j=0
processedFileList=()
sameFileList=()
sameFile=''

for fileA in /usr/lib/*.*
do
processedSign=false
for element in ${processedFileList[*]}
do
if [ $element = $fileA ]
then
processedSign=true
break
fi
done

if [ $processedSign = false ]
then
sameFile=''
processedFileList[i]=$fileA
sameFile+=$fileA
sameFile+=' '
i=$[$i+1]
for fileB in /usr/lib/*.*
do
if [ $fileA != $fileB ]
then
if diff -q $fileA $fileB;
then
processedFileList[i]=$fileB
sameFile+=$fileB
sameFile+=' '
i=$[$i+1]
fi
fi
done
sameFileList[j]=$sameFile
j=$[$j+1]
fi
done


for((i=0;i<${#sameFileList[@]};i++))
do
echo ${sameFileList[i]}
done

end=$(date +%s)
runningTime=$(( end - start))
echo "The running time is $runningTime"