作为一个运维工程师(数据库工程师) ,管理和维护成百上千台服务器是很正常的事情,脚本就成为了
不可或缺的工具,shell是最基本的了,工作中经常用到,自己讲偶尔犯错的部分记录一下,警示自己。
另外,shell 是Linux原生的交互工具,使用方便,简单,可以在运维工作中 ,大大的提高工作效率
,对日常简单的任务都可以由shell处理 , 哈哈 。 当然也有不合适的地方。比如说:
需要比数组更复杂的数据结构
出现了复杂的转义问题
有太多的字符串操作
性能问题
任务代码比较多 ...
注意 : 这个时候 选择 Python 会是一个明智的选择
a. 单引号内部的 变量 是完全按照字符展示的,不会替换成为变量的值的。
b. 双引号中的变量会进行变量值替换。
#!/bin/bash
for x in $( seq 1 10 )
do
echo '$x : ' ," $x !"
done
输出:
$x : , 1
$x : , 2
$x : , 3
$x : , 4
$x : , 5
$x : , 6
$x : , 7
$x : , 8
$x : , 9
$x : , 10
和 $() 是对等的,但是后者更清晰,特别是多层次嵌套的时候。 反单引号在有些字体里
跟正单引号很相似。 $()能够内嵌使用,而且避免了转义符的麻烦。
for x in $( seq 1 10 ) 和 for x in `seq 1 10 ` 是对等的
比如要是 输出 : 1-2-3-4 。 明显第二个更加简单方便,并且不需要转义
echo "1-`echo 2-\`echo 3-\\\`echo 4\\\`\``"
echo "1-$(echo 2-$(echo 3-$(echo 4)))"
以下三个方式都可以的
3.1 while
while read line
do
echo $line
done < test
3.2 cat | while
cat filename | while read line
do
echo $line
done
3.3 for
注意 此方式在行中有空格的时候 会变为多行
for line in `cat filename `
do
echo $line
done
整数变量加减乘除运算 , 这个我经常记混,所以特别记录以下
for x in ` seq 1 10 `
do
echo $x " " $((${x} + 10)) " " $(($x * 10))
done
输出 :
1 11 10
2 12 20
3 13 30
4 14 40
5 15 50
6 16 60
7 17 70
8 18 80
9 19 90
10 20 100
把相同的功能模块定义为function , 可以提高代码的重用性和可读性,如下读取文件代码 :
GetFileLines() {
local sum=0
local line=””
while read line ; do
sum=$((${sum} + ${line}))
done
echo ${sum}
}
使用[[]]能避免像异常的文件扩展名之类的问题,而且能带来很多语法上的改进
,而且还增加了很多新功能:
|| 逻辑or(仅双中括号里使用)
&& 逻辑and(仅双中括号里使用)
< 字符串比较(双中括号里不需要转移)
-lt 数字比较
= 字符串相等
== 以Globbing方式进行字符串比较(仅双中括号里使用,参考下文)
=~ 用正则表达式进行字符串比较(仅双中括号里使用,参考下文)
-n 非空字符串
-z 空字符串
-eq 数字相等
-ne 数字不等
单中括号:
[ $x -gt 3 ]
双中括号
[[ $x > 3 ]] #右侧如果是变量比较,一定要加上双引号
使用双中括号带来的好处用下面几个例子最能表现:
t="abc123"
[[ "$t" == abc* ]] # true (globbing比较)
[[ "$t" == "abc*" ]] # false (字面比较)
[[ "$t" =~ [abc]+[123]+ ]] # true (正则表达式比较)
[[ "$t" =~ "abc*" ]] # false (字面比较)
注意,从bash 3.2版开始,正则表达式和globbing表达式都不能用引号包裹。如果你的表达式里有空格
,你可以把它存储到一个变量里:
r="a b+"
[[ "a bbb" =~ $r ]] # true
按Globbing方式的字符串比较也可以用到case语句中:
case $t in
abc*) <action> ;;
esac
${#string} $string的长度
${string:position} 从位置$position开始提取子串
${string:position:length} 从位置$position开始,长度为$length的子串
${string#substring} 从开头, 删除最短匹配$substring的子串
${string##substring} 从开头, 删除最长匹配$substring的子串
${string%substring} 从结尾, 删除最短匹配$substring的子串
${string%%substring} 从结尾, 删除最长匹配$substring的子串
${string/substring/replacement} $replacement,替换第一个匹配的$substring
${string//substring/replacement} $replacement, 代替所有匹配的$substring
${string/#substring/replacement} $string的前缀匹配$substring ,替换
${string/%substring/replacement} $string的后缀匹配$substring, 替换
Bash里有各种各样操作字符串的方式
基本用户
f="path1/path2/file.ext"
len="${#f}" # = 20 (字符串长度)
# 切片操作: ${<var>:<start>} or ${<var>:<start>:<length>}
slice1="${f:6}" # = "path2/file.ext"
slice2="${f:6:5}" # = "path2"
slice3="${f: -8}" # = "file.ext"(注意:"-"前有空格)
pos=6
len=5
slice4="${f:${pos}:${len}}" # = "path2"
替换操作
f="path1/path2/file.ext"
single_subst="${f/path?/x}" # = "x/path2/file.ext"
global_subst="${f//path?/x}" # = "x/x/file.ext"
删除头部或尾部
f="path1/path2/file.ext"
# 删除字符串头部
extension="${f#*.}" # = "ext"
# 以贪婪匹配方式删除字符串头部
filename="${f##*/}" # = "file.ext"
# 删除字符串尾部
dirname="${f%/*}" # = "path1/path2"
# 以贪婪匹配方式删除字符串尾部
root="${f%%/*}" # = "path1"
假设变量$str的值为foo-bar-baz,如果你想按-分割成多个段并遍历它,可以使用read命令,
并且设置 IFS 的值为-:
$ IFS=- read -r x y z <<< "$str"
这里我们使用read x命令从标准输入读取内容,分割后并依次保存到x y z变量中。其中,$x 为foo,
$y 为 bar, $z 为 baz。 另外要留意的一处是here-string操作符<<<,可以很方便地将字符串传递
给命令的标准输入。在这个例子中,$str的内容传给 read 命令的标准输入。
$ IFS=- read -ra parts <<< "foo-bar-baz"
在这里,-a 选项告诉read命令将分割后的元素保存到数组parts中。随后,你可以通过${parts[0]}
${parts[1]}和${parts[0]}来访问数组的各个元素,或者通过${parts[@]}来访问所有元素。
使用tr 命令替换
awk -F "" -v OFS="" '$NF="" {print}1'
shell 使用比较方便,系统原生,属于轻量级脚本,但是不得不承认,语法上面不如Python 简洁,另外shell 用起来很多地方容易出错。