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
输入:
-
1 . 普通的做法
echo "What's your name?" read Name # 这里不需要声明新变量 echo Hello, $Name! -
2 . read用法
read -p "File: " file #-p表示显示提示符 echo "The file is : $file" -
3 . cat用法
cat - $file <<<"this is title">$file.new #将<<<后面的当做标准输入,输入到前面的命令里,-代表临时文件,即输入流,然后<<<后面的内容及其$file的内容一并放入$file.new中。<<<后面的内容在$file内容的前面嵌入
多语句组合
&&: 满足短路原则,即第一个命令返回失败时不会执行第二个命令||: 满足短路原则,即第一个命令返回成功时不会执行第二个命令-
echo “Always executed” || echo “Only executed if first command fails”;: 不短路,不管第一个命令是否返回成功,均会执行第二个命令
echo “Always executed” && echo “Only executed if first command does NOT fail”
echo “Always executed1” ; echo “Always executed2”
管道和重定向
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 == hel? ]] 结果为假
[[ hello == hell? ]],?表示只匹配一个字符,而*表示配配多个字符
ls a? ### a1
ls a* ### a1 access_log
-
&&、||、<和>操作符能够正常存在于[[ ]]条件判断结构中,但是如果出现在[ ]结构中的话,会报错。比如可以直接使用if [[ $a != 1 && $a <= 5 ]], 如果不使用双括号, 则为if [ $a -ne 1] && [ $a -le 5 ] 或者if [ $a -ne 1 -a $a -le 5 ]
文件的判断
-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的文件末尾追加这三句话。