1 变量

变量定义:

var_test1="hello"

注意定义和赋值时=两边均不能有空格,且变量名前不能加$

变量使用:

echo ${var_test1}
str1="${var_test1} world"

加上美元符后的变量会被替换为其值。注意,单引号中的不会被替换

比如

a=123
echo $a
echo "$a"
echo '$a'

123
123
$a

命令执行结果赋给一个变量:

lines=`wc -l 1.txt`  # 这里lines就被赋值为了1.txt的行数
lines="$(wc -l 1.txt)"  # 单撇号不能嵌套,可用这种包含在内

格式化变量:

echo 23 | awk {printf("%05d", $0);} # 00023

字符串截取:

${var_test1:1:3}

会得到”ell”,即从索引1开始取3个字符

输出

shell中的输出直接用echo即可

echo "hello word"
等同于
echo hello word

输入:

多语句组合

管道和重定向

cmd1 | cmd2: 管道,第一个命令的输出会直接作为第二个命令的标准输入来执行
python test.py < in.txt: 输入重定向,将从in.txt读取输入而非标准输入流
echo "hello" > out.txt: 输出重定向,将前一个命令的输出定向到文件out.txt中(创建新文件并写入)
echo "hello" >> append.txt: 输出重定向,将前一个命令的输出定向到文件append.txt中(追加到文件末尾)
echo "hello" 2> err.txt: 错误流重定向,将前一个命令的错误流输出定向到文件err.txt中(创建新文件并写入)
echo "hello" 2>> err.txt: 错误流重定向,将前一个命令的错误流输出定向到文件err.txt中(追加到文件末尾)

2 . 判断

最简单的判断逻辑是:

if [ condition1 ]; then
     statement1
elif [ condition2 ]; then
    statement2
else
    statement3
fi
# 或者用test
if test condition1 ; then
     statement1
fi

注意:condition两边与[]之间必须至少有一个空格

判断条件

hell中判断条件不同于其他语言中的<,>,==,<=,>=那么直接,常见的有下列几种:

-eq   等于(==)
-ne   不等于(!=)
-gt   大于(\>)
-lt   小于(\<)
-le   小于等于
-ge   大于等于
-z    空串
-n    非空串
==    两个字符相等
!=    两个字符不等

组合判断

-a      且
-o      或

特殊用法[[ ... ]]

[[ hello == hell? ]]结果为真
	[[ hello == hel? ]] 结果为假 

[[ hello == hell? ]]?表示只匹配一个字符,而*表示配配多个字符

	ls a?    ### a1
	ls a*    ### a1  access_log

文件的判断

-f     判断后面是否为一个文件            if [ -f fname ]
-d     判断后面是否为一个目录            if [ -d fname ]
-e     判断后面对应的文件是否存在        if [ -e fname ]
-s     判断文件是否存在且不为空          if [ -s fname ]

switch case

case "$Variable" in
    # 列出需要匹配的字符串
    0) echo "There is a zero.";;
    1) echo "There is a one.";;
    *) echo "It is not null.";;
esac

3 . 循环

for 循环

# {1..3} == `seq 1 3`
for Variable in {1..3}
do
    echo "$Variable"
done

或传统的”for循环”,但需要加两层括号(两层的小括号内可以写C语言中的语句):

for ((a=1; a <= 3; a++))
do
    echo $a
done

在其他命令的结果上执行for循环:

for Output in `ls` ;
do
    cat $Output
done

while 循环

while [ condition ]
do
    echo "loop body here..."
    break
done

4. 命令行

$#     命令行参数个数
$0     当前脚本名
$n     第n个参数值,n可取1,2,3...
$@     所有命令行参数
$?     上一个命令的返回值

5. 其他常用命令

# 打印每行中 ',' 之前内容
cut -d ',' -f 1 file.txt

# 将 file.txt 文件所有 'okay' 替换为 'great', (兼容正则表达式)
sed -i 's/okay/great/g' file.txt

# shell中不支持浮点数除法运算,可使用awk实现浮点除法
a=3
b=4
c=`awk 'BEGIN{printf "%.2f",('$a'/'$b')}'`  # 单引号内的变量不能被替换,因此需要将变量单独放在引号外

sort
-k 指定比较的列(从1开始)
-n 数值比较
-r 倒序
-o filename 输出到文件(可用此选项输出到输入文件)
-f  不区分大小写排序
-c 检查是否已排序好,如果未排序好则输出第一个未按序的行
-M 按月份排序
-b 忽略前导空格
-u 得到不重复的行

多列排序:sort -k1,1 -k3nr,3

字符串的其他操作

${#string}	$string的长度

${string:position}	在$string中, 从位置$position开始提取子串

${string:position:length}	在$string中, 从位置$position开始提取长度为$length的子串

${string#substring}	    从变量$string的开头, 删除最短匹配$substring的子串

${string##substring}	从变量$string的开头, 删除最长匹配$substring的子串

${string%substring}	    从变量$string的结尾, 删除最短匹配$substring的子串

${string%%substring}	从变量$string的结尾, 删除最长匹配$substring的子串

${string/substring/replacement}	    使用$replacement, 来代替第一个匹配的$substring

${string//substring/replacement}	使用$replacement, 代替所有匹配的$substring

${string/#substring/replacement}	如果$string的前缀匹配$substring, 那么就用$replacement来代替匹配到的$substring

${string/%substring/replacement}	如果$string的后缀匹配$substring, 那么就用$replacement来代替匹配到的$substring

字符串分割:

例 1

可以参考2017.12.1.Shell分割迭代字符串

a="one,two,three,four"

# 要将$a分割开,可以这样:
OLD_IFS="$IFS" 
IFS="," 
arr=($a) 
IFS="$OLD_IFS" 
for s in ${arr[@]} 
do 
    echo "$s" 
done
# 后面的可以直接改为只取${arr[1]}

例 2

test_result.txt

/share/xvs/results/s2017-12-15-061613/performance/up_linpack_vnic_64_g32e/rcp-replay-log/43380replay.log

Total Test: 13
Passed Tests: 0
Failed Tests List: 1,2,3,4,5,6,7,8,9,10,11,12,13
expected_end_fail and segment_error: 12
segment_error: 1

脚本内容:

failed_list=`grep "Failed Tests List" $1《这里是文件名》 | sed "s/Failed Tests List: //"`

while IFS=',' read -ra ADDR;do
    for i in "${ADDR[@]}";do
         echo $i
    done
done <<< "$failed_list"

“$failed_list”表示1,2,3,4,5,6,7,8,9,10,11,12,13

.

输出结果:

[root@ccd-nfs tem]# ./1.sh test_result.txt
1
2
3
4
5
6
7
8
9
10
11
12
13

cat和EOF结合使用具有追加功能

cat

当Cat没有输入打印文件,默认从标准输入获取内容

[root@ccd-nfs tmp]# cat >> /share/xvs/results/fenglin/tmp/test.txt
123
456
789

123 456 789 是手动输入的

这时候/share/xvs/results/fenglin/tmp/test.txt的内容就是增加了123 456 789

EOF

Shell中通常将EOF<< 结合使用,表示后续的输入作为子命令或子Shell的输入,直到遇到EOF为止,再返回到主调Shell。
我们经常在shell脚本程序中用<<EOF重定向输入,将我们输入的命令字符串作为一个执行程序的输入,这样,我们就不需要在那个程序环境中手工输入命令,以便自动执行我们需要的功能

需要注意的是,第一个EOF必须以重定向字符«开始,第二个EOF必须顶格写,否则会报错

cat >/share/xvs/results/fenglin/tmp/test.txt <<EOF
	start
	hello word !
	finish
EOF

将/share/xvs/results/fenglin/tmp/test.txt文件的内容变成以下三句话

	start
	hello word !
	finish
.                                                                                                                                                                          
cat >>/share/xvs/results/fenglin/tmp/test.txt <<EOF
	start
	hello word !
	finish
EOF

在/share/xvs/results/fenglin/tmp/test.txt的文件末尾追加这三句话。