Shell
Linux的shell有很多种,大多数linux发行版的默认登录shell是BASH。
查看当前使用的shell:
echo $SHELL
echo $0
查看安装了哪些shell:
cat /etc/shells
设置登陆shell:
$chsh -s $(which shellname)
shell分为登陆shell和交互式shell:
# 输出有i的就是交互shell
$echo $-
非交互登陆shell:
- 先运行系统配置文件/etc/profile(调用/etc/bash.bashrc和/etc/profile.d/*.sh)
- 然后运行用户配置文件~/.profile(调用~/.bashrc和~/bin)
- 最后退出用户登陆~/.bash_logout
交互非登陆shell:
- 先运行/etc/bash.bashrc(调用/etc/bash_completion(调用/etc/bash_completion.d/*.sh))
- 然后运行~/.bashrc(调用~/.bash_aliases和~/bash.d和~/bin)
shell相关项目
bash-it
大部分发行版默认使用bash,无需额外安装。
bash的优化项目bash-it:
https://github.com/Bash-it/bash-it
zsh
oh-my-zsh
https://github.com/robbyrussell/oh-my-zsh
fish-shell
https://github.com/fish-shell/fish-shell
oh-my-fish
https://github.com/oh-my-fish/oh-my-fish
thefuck
一个纠正shell命令输错的命令
https://github.com/nvbn/thefuck
shellcheck
一个debug脚本的工具.
https://github.com/koalaman/shellcheck
shell script
基本语法
#!/usr/bin/env bash
command1 && command2 # 当command1执行成功(返回0)才会执行command2
command1 || command2 # 当command1执行失败(返回非0)才会执行command2
shell注释
单行注释:
# comment
多行注释:
:<<!EOF!
comment
!EOF! can be any symbol and character.
!EOF!
shell关键字和特殊符号
三个特殊命令
echo
printf
test
关键字
function
shell运算符和优先级
原生shell不支持数学运算,可以通过expr来实现.
# expr表达式内部运算符前后要空格.
val=`expr 2 + 2`
算术运算符
+
-
* # `expr $a \* $b`, 不要转义
/
%
= # a=$b
== # [ $a == $b ] , 需要中括号,需要空格
!= # [ $a != $b ], 同上
关系运算符
# 只支持数字,不支持字符串.需要中括号和空格
-eq
-ne
-gt
-lt
-ge
-le
布尔运算符
# 符合短路和斷路原则
! # [ !false ]
-o # [ exp1 -o exp2 ], 有一个为true就返回true
-a # [ exp1 -a exp2], 两个都是true才返回true
逻辑运算
||
&&
字符串运算符
=
!=
-Z # 字符串长度为0返回true
-n # 字符串长度为0返回false
str # [ $a ], 字符串不为空返回true
文件测试运算符
-b
-c
-d
-f
-g
-k
-p
-u
-r
-w
-x
-s
-e
shell数据结构和变量
变量类型:
局部变量
环境变量
shell变量
定义变量:
等号前后不能有空格
不能用数字开头命名变量
不能用标点符号和关键字
var=`ls /etc` # 返回的是stdout+stderr
var=$(ls /etc) # 返回的是stdou+stderr
使用变量:
$var
${var}
# 使用双引号
var1="pre${var}suf
var2="$var"
只读变量:
使用readonly定义只读变量,不能再重新赋值
var=value
readonly var
删除变量:
使用unset删除变量,被删除的变量不能使用.
var=value
unset var
变量操作:
${var/old/new} # 将变量中的old替换成new.
${var:start:end} # 获取变量的start到end个字符,相当于var[start:end],下标从0开始.
字符串类型:
单引号的字符串是原样输出,其中的变量是无效的,里面不能有单引号.
var='this is string'
双引号的字符串里面可以有变量,可以出现转义字符.
var="this is string"
"outer \"inner string\" string"
获取字符串长度
var="this is tring"
echo ${#var}
字符串切片
var="this is string"
${var:start:end} # 相当于var[start:end], 下标从0开始
获取pattern在string中的起始下标
string="this is string"
`expr index "$string" pattern`
数字类型:
数组:
shell控制流
# [[ 里面不能用 -o/-a ]]
if [[ $status1 -eq 0 ]] || [[ $status2 -eq 0 ]]
if [[ $status1 -eq 0 ]] && [[ $status2 -eq 0 ]]
# [ 单层可以用-o/-a ]
if [ $status1 -eq 0 -o $status2 -eq 0 ]
if
if []; then command; ...; fi
if condition
then
command
fi
[]/test 中必须为执行的命令的stdout+stderr.
if [ ! `cat file | grep pattern | wc -l` ]
if [ ! 0 ] 此时0为真, [ ! 0 ]为假
if command 看返回码$?, 0表示真,其它表示假.
if-else
if condition; then command; ...; else command; fi
if condition
then
command
else
command
fi
if-elif-else
if condition; then command; ...; elif condition; then command; ...; else command; fi
if condition
then
command
elif condition
then
command
else
command
fi
while
while condition; do command;...; done
while condition
do
command
done
# 无限循环
while :
do
command
done
# 无限循环
while true
do
command
done
for
for ((i=1; i<=100; i++))
for i in {1..100}
for i in `seq 1 100`
for VAR in ${1,2,3,...}; do command; ...; done
for var in item1 item2 ... itemN
do
command
done
# 无限循环
for (( ; ; ))
until
until condition; do command; ...; done
until condition
do
command
done
case
case $VAR in
val1)
command
...
;;
val2)
command
...
;;
esac
break
continue
shell函数
return只是返回当前函数,不退出主程序
exit直接退出主程序
通过关键字function定义函数:
function Name { // ()可省略
function Name() {
...
# 如果不显示调用return返回,则函数返回最后一条命令的结果
return $?
}
也可以直接定义函数:
Name() {
...
}
函数返回码:
$?
函数参数:
$1 - $9 可以在函数内部获取调用函数时候传递进来的9个参数
${10} - ${100} 获取第十个参数和后面的参数
特殊字符:
$# 表示传递到脚本的参数个数,不包括程序本身
$* 传入所有参数
$@ 传入所有参数
$$
$!
$-
输入输出和重定向
stdout和stdin重定向到一个地方:
1> 只重定向stdout
2> 只重定向stderr
2>&1 同时重定向stdout+stderr
main > 2>&1 log1.log | tee log2.log # 同时重定向到两个文件
main 2>&1 | tee ${LOG} # 同时将stdout和stderr输出到终端和日志文件.