Linux Shell 讲义
Variables
变量类型
分为环境变量(全局变量) , 普通变量(局部变量) 和 特殊位置参数变量
环境变量(全局变量)
- 可以在创建它们的shell及其派生出来的任意子进程shell中使用,环境变量又可分为自定义环境变量和bash内置环境变量。
- 环境变量一般是指用export导出的变量。
- 设置环境变量的相关配置文件
-
用户的环境变量
- ~/.bash_profile
- ~/.bashrc
-
全局的环境变量
- /etc/profile
- /etc/bashrc
- /etc/profile.d/*
- 如果要在登录后初始化或加载内容,就把脚本放在该目录下,不需要加可执行权限。
- 设置登录提示
1. echo "welcome " >> /etc/motd
2. echo “welcome” > /etc/profile.d/login.sh
普通变量(局部变量)
- 只能在创建它们的shell函数或者shell脚本中使用
- 变量赋值,分为三种:xxx=value,xxx=‘value’,xxx=“value”,把命令结果赋值给一个变量,它们的区别:
xxx=value
- 建议 连续的数字 或 连续的字符串 赋值时,使用这个赋值方式。
num=123
str=hello
echo "num:"${xxx}
echo "str:"${str}
# output
# num:123
# str:hello
xxx=‘value’
- 希望原样打印引号里面的内容的时候,使用这个赋值方式。
- 示例,参照 grammar/vaiable.sh/variable1 函数
a=192.168.1.2
b='192.168.1.2-$a'
c="192.168.1.2-$a"
echo "a=$a"
echo "b=$b"
echo "c=${c}"
# output:
# a=192.168.1.2
# b=192.168.1.2-$a
# c=192.168.1.2-192.168.1.2
xxx=“value”
- 建议字符串中带有空格 或 希望解析内容中的变量 的时候,使用这种形式
- 示例,参照 grammar/vaiable.sh/variable1 函数
a="this is a test"
b="pwd is $(pwd)"
echo "a:"${a}
echo "b:"${b}
# output:
# a:this is a test
# b:pwd is /home/zhangrj/git/pgr/shell/grammar
把命令结果赋值给一个变量
- 使用 ``
- 使用 $()
- 示例:
pwd1=`pwd`
pwd2=$(pwd)
echo "pwd1:"${pwd}
echo "pwd2:"${pwd}
# output
# pwd1:/home/zhangrj/git/pgr/shell/grammar
# pwd2:/home/zhangrj/git/pgr/shell/grammar
附注:
案例:
grep是如何引号变量的值的
- 参照 strings/grep.sh/variable1 函数 grep 过滤字符串时给过滤的内容加引号
cat variable.log
teachers
oldboy
OLDBOY="teachers"
echo "\"$OLDBOY\":"$(grep "$OLDBOY" grep1.log)
echo "'$OLDBOY':"$(grep '$OLDBOY' grep1.log)
echo "$OLDBOY:"$(grep $OLDBOY grep1.log)
# output
# "teachers":teachers
# 'teachers':
# teachers:teachers
awk 是如何引号变量的值的
- 变量定义为单引号的时候,awk是如何引用变量的值
- 参照 strings/awk.sh/awk1
ETT='oldgirl' echo "'${ETT}'-\"$ETT\"":$(awk 'BEGIN {print "$ETT"}') echo "'${ETT}'-$ETT":$(awk 'BEGIN {print $ETT}') echo "'${ETT}'-'$ETT'":$(awk 'BEGIN {print '$ETT'}') echo "'${ETT}'-\"'$ETT'\"":$(awk 'BEGIN {print "'$ETT'"}') # output # 'oldgirl'-"oldgirl":$ETT # 'oldgirl'-oldgirl: # 'oldgirl'-'oldgirl': # 'oldgirl'-"'oldgirl'":oldgirl
- 变量定义为双引号的时候,awk是如何引用变量的值
- 参照 strings/awk.sh/awk3
ETT="oldgirl" echo "\"${ETT}\"-\"$ETT\"":$(awk 'BEGIN {print "$ETT"}') echo "\"${ETT}\"-$ETT":$(awk 'BEGIN {print $ETT}') echo "\"${ETT}\"-'$ETT'":$(awk 'BEGIN {print '$ETT'}') echo "\"${ETT}\"-\"'$ETT'\"":$(awk 'BEGIN {print "'$ETT'"}') # output # oldgirl-"oldgirl":$ETT # oldgirl -'oldgirl'-oldgirl: # oldgirl -'oldgirl'-'oldgirl': # oldgirl - "'oldgirl'":oldgirl
- 变量直接定义的时候,awk是如何引用变量的值
- 参照 strings/awk.sh/awk2
ETT=oldgirl echo "${ETT}-\"$ETT\"":$(awk 'BEGIN {print "$ETT"}') echo "${ETT} -'${ETT}'-$ETT":$(awk 'BEGIN {print $ETT}') echo "${ETT} -'${ETT}'-'$ETT'":$(awk 'BEGIN {print '$ETT'}') echo "${ETT} - \"'$ETT'\"":$(awk 'BEGIN {print "'$ETT'"}') # output # "oldgirl"-"oldgirl":$ETT # "oldgirl"-oldgirl: # "oldgirl"-'oldgirl': # "oldgirl"-"'oldgirl'":oldgirl
- 先用echo加符号输出变量,然后通过管道给awk.
ETT="oldgrid" echo "$ETT" |awk '{print $0}' # output # oldgrid
sed 是如何引号变量的值的
cat sed.log
teachers
oldboy
OLDBOY="teachers"
echo "\"$OLDBOY\"":"$(sed -n /"$OLDBOY"/p sed.log)"
echo "$OLDBOY":"$(sed -n /$OLDBOY/p sed.log)"
echo "'$OLDBOY'":"$(sed -n /'$OLDBOY'/p sed.log)"
# output
# "teachers":teachers
# 'teachers':
# teachers:teachers
特殊位置参数变量
分为$0,$n,$#,$*,$@
$1$4…$9${10}… 和 $# 特殊变量
- 参照 grammar/variable.sh/variable4
echo "echo $# $(echo \${1..15})" > n.sh
echo 'echo $# $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}' >> n.sh
cat n.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
sh n.sh {a..z}
# output
# a b c d e f g h i a0 a1 a2 a3 a4 a5
# a b c d e f g h i j k l m n o
# Note:
# 位置变量参数数字大于9时,需要用大括号将数字括起来.
$0 特殊变量
- 参照 grammar/variable.sh/variable5 函数
echo 'echo $0' > n5.sh
echo 'echo "dirname:"$(dirname "$0")' >> n5.sh
echo 'echo "basename:"$(basename "$0")' >> n5.sh
# cat n5.sh
# echo $0
# echo "dirname:"$(dirname "$0")
# echo "basename:"$(basename "$0")
sh n5.sh
# output
# n5.sh
# dirname:.
# basename:n5.sh
sh `pwd`/n5.sh
# output
# /home/zhangrj/git/pgr/shell/grammar/n5.sh
# dirname:/home/zhangrj/git/pgr/shell/grammar
# basename:n5.sh
$@,$* 特殊变量
- @ 不 加 引 号 跟 @不加引号跟 @不加引号跟*是一样的
- $@加引号表示把所有参数视为单一参数
- 参照 grammar/variable.sh/variable6 函数
Shell 进程中的特殊状态变量
分为$?,$$,$!,$_
$$ 特殊状态变量
- 参照 grammar/variable.sh/variable7 函数
- 示例:使用$$实现系统中多次执行某一个脚本后的进程只有一个
cat > n6.sh << EOF
#!/bin/sh
pidpath=/tmp/exec.pid
if [ -f "\$pidpath" ]
then
kill \`cat \$pidpath\` > /dev/null >& 1
rm -f \$pidpath
fi
echo \$\$ > \$pidpath
sleep 300
EOF
变量相关操作
查看
- set:输出所有的的变量,包括全局和局部。
- env:只显示全局变量。
- declare(替代早期的typeset):输出所有的变量,函数,整数和已经导出的变量。
设置环境变量
- export xxx=“123”
- xxx=“123”;export xxx
- declare -x xxx=“123”
Bash内置变量命令
常用的内部命令有:echo,eval,exec,export,read,shift
echo
示例:-n 不换行输出内容
cat > n8.sh << EOF
#!/bin/sh
echo oldboy;echo oldgirl
echo -n oldboy;echo oldgirl
EOF
sh n8.sh
# output
# oldboy
# oldgirl
# oldboyoldgirl
示例: -e 解析转义字符
cat > n9.sh << EOF
#!/bin/sh
echo "oldboy\toldgirl\noldboy\toldgirl"
echo
echo -e "oldboy\toldgirl\noldboy\toldgirl"
EOF
sh n9.sh
# output
# oldboy\toldgirl\noldboy\toldgirl
#
# oldboy oldgirl
# oldboy oldgirl
eval
- 格式 eval args
- shell 读入参数args,并将它们组合成一个新的命令,然后执行
示例:
cat > n10.sh << EOF
echo \\\$\$#
eval "echo \\\$\$#"
EOF
sh n10.sh arg1 arg2
# output
# $2
# args
exec,exec命令和重定向
-
图示:
-
格式:exec 命令参数
-
说明:exec 命令在不创建子进程的前提下,转去执行指定的命令,执行完成之后,该进程也就结束了(也就是最初的shell)
示例:
cat > n11.sh << EOF
seq 5 > /tmp/tmp.log
exec < /tmp/tmp.log
while read line
do
echo \$line
done
echo ok
EOF
read
- 格式:read 变量名表
- 说明:从标准输入读取字符串信息,传给shell程序内部定义的变量.
- 示例:
cat > r1.sh << EOF
read -t 5 -p "please input two variables:" a b
echo "\$a \$b " |awk '{print (\$1,\$2,\$1 + \$2)}'
EOF
sh r1.sh
shift
- 格式:shift-Shift positional parameters
- 说明:shift安装如下方式重新命名所有的位置参数变量,也就是$2变成$1,$3变成$2
- 示例:
cat > n12.sh << EOF
echo \$1 \$2
if [ \$# -eq 2 ];then
shift
echo \$1
fi
EOF
sh n12.sh 1 2
# output
# 1 2
# 2
shell变量子串
${#parameter} 获取字符串长度
示例
cat > n13.sh << EOF
string="hello,everyone my name is xiaoming"
len=\${#string}
echo "len:"\$len
EOF
sh n13.sh
# output
# len:34
示例:使用其他方式:expr,参照 strings/expr.sh/expr1 函数
cat > s1.sh << EOF
string="hello,everyone my name is xiaoming"
len=\`expr length "\$string"\`
echo "len:"\$len
EOF
sh s1.sh
# output
# len:34
示例:使用其他方式:awk,参照 strings/expr.sh/awk4 函数
cat > a1.sh << EOF
string="hello,everyone my name is xiaoming"
echo "len_1":\$(echo \${string} |awk '{print length(\$0)}')
echo "len_2":\$(echo \${string} |awk -F "" '{print NF}')
EOF
sh a1.sh
# output
# len:34
# len:34
${parameter#word},${parameter##word},${parameter%word},${parameter%%word} 四种获取字串的方法
- 参照 strings/variable.sh/variable14 函数
- 示例
cat > n14.sh << EOF
string="abcABC123ABCabc"
echo "str:"\${string}
echo "one_1:"\${string#a*C}
echo "one_2:"\${string#a*c}
echo
echo "two_1:"\${string##a*C}
echo "two_2:"\${string##a*c}
echo
echo "three_1:"\${string%a*C}
echo "three_2:"\${string%a*c}
echo
echo "four_1:"\${string%%a*C}
echo "four_2:"\${string%%a*c}
EOF
sh n14.sh
# output
# str:abcABC123ABCabc
# one_1:123ABCabc
# one_2:ABC123ABCabc
#
# two_1:abc
# two_2:
#
# three_1:abcABC123ABCabc
# three_2:abcABC123ABC
#
# four_1:abcABC123ABCabc
# four_2:
${parameter/pattern/string},${parameter//pattern/string} 字符串替换
示例:
cat > n15.sh << EOF
string="I am oldboy,yes , oldboy"
echo "str:"\${string}
echo
echo "substr_1:"\${string/oldboy/oldgirl}
echo
echo "substr_2:"\${string//oldboy/oldgirl}
EOF
sh n15.sh
# output
# substr_1:I am oldgirl,yes , oldboy
# substr_2:I am oldgirl,yes , oldgirl
获取子串
示例:使用expr获取子串
参照 strings/expr.sh/expr2函数
cat > s2.sh << EOF
string="hello,everyone my name is xiaoming"
substr=\`expr substr "\$string" 1 5\`
echo "substr:"\${substr}
EOF
sh s2.sh
# output
# hello
示例:使用awk获取子串
参照 strings/awk.sh/expr2函数
shell特殊扩展变量
![avatar][shell特殊扩展变量]
- 示例
cat > n16.sh << EOF
test_A=
echo "test_A:"\${test_A}
result_A=\${test_A:-UNSET}
echo "result_A_1:"\$result_A",test_A_1:"\${test_A}
result_B=\${test_A:=UNSET}
echo "result_B_1:"\$result_B",test_A_1:"\${test_A}
EOF
sh n16.sh
# output
# test_A:
# result_A_1:UNSET,test_A_1:
# result_B_1:UNSET,test_A_1:UNSE
变量的数值计算
![avatar][shell常用的算术运算符号]
![avatar][shell常见的算术运算命令]
(()) 数值运算,用于整数运算
![avatar][双小括号((xxx))的操作方法]
示例:
echo $(( 1 + 1)) # output:2
((i=5)) # 定义变量
((i = i * 2)) # 对定义的i变量进行运算
echo $i # 获取i的值,并且打印
a=8
echo $((a=a+1)) # output 9,a的值为9
echo $(a+1) #output 9,a的值为8
echo $((3 < 8)) # output 1
echo $((8 > 7 && 5 == 5)) #output 1
if ((8 > 7 && 5 == 5))
then
echo yes
fi
#output yes
# 总结:
# "(())" 在执行命令的时候不需要加$符号,但是要输出,就要加$符号
# "(())" 里的所有字符之间没有空格,有一个空格或多个空格都不会影响结果
let 运算命令的用法
- 语法格式:let赋值表达式
示例:
i=2
i=i+8 #没有使用let进行赋值
echo $i # 没有使用let,i直接输出i+8
unset i
i=2
let i=i+8 # 使用let对i进行赋值,等同于((i=i+8))
echo $i # i输出为10
expr 用于算术运算
- 语法格式 expr Expression
- 使用expr的使用应该注意
- 运算符及用于计算的数字左右都至少有一个空格,否则会报错
- 使用乘号时,必须用反斜杠屏蔽其特殊含义
- expr 在shell中可配合变量进行计算,但需要用反引号(``)将计算表达式括起来
- 利用expr做计算的时候变量必须是整数的规则,可以判断一个变量是整数还是字符串
示例:
expr 2 + 2 # output 4
expr 2 \* 4 # output 8,*号用\来转义
i=5
i=`expr $i + 7`
echo $i # output 12
示例: 判断一个变量或字符串是否是整数
- 使用expr运算的返回值判断 , 参照 strings/expr.sh/expr3函数
cat > s3.sh << EOF
read -p "input:" i
expr \$i + 6 &> /dev/null
if ((\$?==0))
then
echo yes
else
echo no
fi
EOF
sh s3.sh
# output
# read
# 123
# yes
- 使用expr match判断 , 参照 strings/expr.sh/expr4函数
cat > s4.sh << EOF
if [[ \`expr match "\$1" "[0-9][0-9]*\$"\` == 0 ]]
then
echo "\$1 is not a num"
else
echo "\$1 is a num"
fi
EOF
sh s4.sh 11 # output 11 is a num
sh s4.sh oldboy # output oldboy is not a num
bc 实现运算功能
- bc 除了支持整数之外,还支持小数运算
- 示例:
echo 3 + 5 |bc #output 8
echo "scale=2;355/113" |bc # 使用scale保留两位小数,3.14
echo {1..10} |tr " " "+" |bc # {1..10}是生成以空格分隔的数字序列,并交给tr将空格替换为+号
seq -s "+" 10 |bc # seq是生成数字序列,-s 指定数字序列之间的分隔符
awk 实现计算
- awk 适用于整数和小数,运算很精确
- 示例:
cat > a3.sh << EOF
echo "7.7 3.8" |awk '{print (\$1 - \$2)}'
echo "3 9" |awk '{print (\$1 + 3) * \$2}'
EOF
sh a3.sh
# output
# 3.9
# 54
declare (typeset) 适用于定义整数变量,直接进行计算
cat > d1.sh << EOF
declare -i A=10 B=7
A=A+B
echo \$A
EOF
sh d1.sh
# output
# 17
$[] 用于整数运算
cat > d2.sh << EOF
i=5
i=\$[i+6]
echo \$i
echo \$[2 * 3]
echo \$[2 ** 3]
EOF
sh d2.sh
# output
# 11
# 6
# 8