符号
shell非常的灵活,一条简单的命令,往往能做很大的事情。别人说,web界面是方便输入的,而shell这种,更方便批量操作。
但是shell有时候非常的晦涩,尤其是大量的符号,比如无限复制进程的fork炸弹代码如下:
:() { :|:& };:
符号虽然抽象,但是功能强大啊。一句胜过千言万语。
另外,听同事讲,shell里面的命令,基本上都是命令。比如 ((i=i+1)),两个括号就是命令,括号内的语法,模仿c语言的。中括号,也差不多。为啥要留空格呢,怕被识别成一个变量???
花括号
定义函数体时,使用。
greet(){
echo "hello",$1
}
#调用
greet zhangsan
代码块:重定向输出
{
echo 1
echo 2
} > 22.txt
# 错误重定向,标准输出无内容,错误输出有内容。
{
echo 1
echo 2
} >&2
代码块:后台运行
不需要单独写个函数,然后封装成脚本后再运行,非常方便。
{
while true;do
echo hello world
sleep 1
done
} &
变量配合
见变量部分。
${hello}
多个参数
就像在bash中,会自动解析*的作用一样,会将花括号内的多个解析出来。
格式:花括号内,用逗号分隔出多项。
可以使用echo 来查看展开的内容。如:echo demo.txt{,.bak}
echo {1,2,3,4}.txt 无论有没有这些文件,都会展开出来。
cp demo.txt{,.bak} # 等价于 cp demo.txt demo.txt.bak
ls cloud/{back,front}*/*.php
# 使用转移符号
echo -e {0..9}{0..9}{0..9}'\n'
# 嵌套使用
echo {{1..20},3}
echo {{a..z},3}
echo {{a..z},3,4,5,{b..g}}
中括号
单中括号[]
判断。配合特殊的语法,来实现逻辑运算。但是,记得中括号内两侧有空格。
[ -z "$1" ] # 如果字符串为空,true
[ "$1" ] # $1字符串不为空时,true
[ -eq $1 10 ] # 数字比较,相等
[ ! -eq $1 10 ] # 感叹号 否定
# 其他符号 -a 且 -o 或
双中括号[[]]
$[]
中括号两侧的空白符号,可有可无。
# 数学表达式计算
$[ 1002/12 ]
echo hello$[ 1024*10 ]
综合
#!/bin/bash
read -p "Please input your score: " score
# 使用了正则
if [[ $score =~ [^0-9] ]] ;then
echo "please input a int"
exit 10
elif [ $score -gt 100 ];then
echo "Your score is wrong"
exit 20
elif [ $score -ge 85 ];then
echo "Your score is very good"
elif [ $score -ge 60 ];then
echo "Your score is soso"
else
echo "You are loser"
fi
小括号
新进程
新起一个进程运行。注意,括号内的变量,在外部访问不到。
(while true;do echo hello world;sleep 1;hello=1;done)
# 停止运行后,echo $hello 是没有输出的。而去掉括号,则可以。
封装返回
同样,使用于函数的返回
demo=$(ls -alh)
echo "$demo" # 原样输出
echo $demo # 输出一行
# 在字符串内,也会被解析。
demo="$(ls -alh)"
双小括号
比如for循环等等。运算符号。
for((i=0;i<10;i++));do
((b=i+2)); # 独立的语句,还不能直接 echo
((c=2*i))
echo $b;
done
`符号
封装返回。跟$( some code )效果类似。
demo=`ls -alh`
echo "$demo"
变量
所有的变量以$前缀。
对于脚本参数,以 $1、$2...数字前缀。 $0当前的脚本
函数类似。
参数个数。
变量运算,参见字符串处理文章。
$?
上次的执行结果。如果正常,则等于0。
# 判断上次执行结果
if [ $? -eq 0 ];then echo ok ;else echo fail ;fi
其实,另外一种方式
感叹号
# 执行最后1条命令
!!
# history中第n条命令
!7
单引号
定义文本变量,其内的$、*等符号,会被保护起来。不会被解析。可以保持文本的换行符号。
保护功能,参加error文章。
双引号
定义文本变量,允许变量注入。可以保持文本的换行符号。
heredoc
3种格式如下:
呼应的并一定非要
EOL,任何和正文不冲突的符号都行。结尾,必须要顶头写,不能有空白字符。
var=hello
<<EOL
多行文本,这个里面的 $var 变量会被 shell解析
EOL
<<'EOL'
多行文本,这个里面的 $var 变量会不会被 shell解析
EOL
<<-EOL
多行文本,这个里面的 $var 变量会被 shell解析,制表符号会被移除。
EOL
# 组合形式 <<-'EOL'
备注:-EOL只能移除制表符号时,空格不会处理。
字符串相加
其实没有相加符号,只要两个文本或变量想靠近即可。
var1=haha
var2=qie
echo $var1$var2
echo "hello"$var2
# 在命令行中
now=`date '+%Y%m%d%H%M%S'`
sed -i 's#ver=version#ver='$now'#g' "$each"
星号 *
bash会自动对*解析,然后转换成多个参数,注入到脚本中。
echo my*.txt
如果想避免解析,那么应该使用单引号、双引号保护起来。
find查找命令,对于下面的*.html,带不带双引号,有很大的区别。不带双引号保护,会被shell解析,然后,
find . -type f -name "*.html"`;do
如果,变量需要内部的命令去解析,也要先用引号保护起来。
# 比如,有个demo.sh 接收一个参数,参数实际上用在内部的sed上。
sed -i "s///g" $1
# 调用bash时, demo.sh 'backend/*.php' ,这个时候,'backend/*.php'在sed命令行中展开。
如果,文件名中有空格,用引号保护,但是*号放在引号外。示例如下:
#Spring 事务一网打尽 (P12. 12.Spring事务传播性之MANDATORY).flv
ls "Spring 事务一网打尽 (P12"*
任意路径**
非常好的命令,能避免很多场景下的for循环。比如,
grep target_string /path/to/**/*.php。
# 查看
shopt
# globstar off
# 开启
shopt -s globstar
开启后,就可以使用任意路径功能了。
好出非常的大,最起码避免先查找文件、然后在for循环里面处理文件了。
如:
grep sometxt cloud/frontend/**/*.php
问号
路径参数中使用。
作用,只能替代一个字符。
touch a1.txt
touch a2.txt
# 查找出a1、a2两个文件
ls a?.txt
# 查找不到内容
ls a??.txt
逻辑运算符号 && ||
跟编程语言的逻辑运算符号类似,也有短路效果。
如下,即判断是否存在hello这个文件夹,如果报错,则提示报错
cd hello && echo exist hello || echo no hello dir
上面那种,是成功、或失败了才会执行相应的分支。
其实还有一种情况,不管成功与否都要执行,其实,就是简单的分号,即可。
domesomething; ding.sh
&
后台
程序需要挂到后台运行。
nohup /yd/td2/shell/import_job.sh >> /yd/td2/runtime/cron/log.txt 2>&1
定时任务,合并输入、错误流
01 00 * * * /yd/td2/shell/import_job.sh >> /yd/td2/runtime/cron/log.txt 2>&1
# 简写形式
ding.sh >& log.txt
ding.sh &> log.txt
# 追加 ,只能按下面这样写
ding.sh &>> log.txt
dockerfile的套路
在dockerfile,很喜欢将多条语句合成1条语句执行。如下,两个示例
方式一:
RUN echo hello && \
echo 1234 && \
echo 4567
方式二:
RUN echo hello \
&& echo 1234 \
&& echo 4567
分号
代码的分隔符号。因为shell的结尾;不是必须的,如果要写在一行的话,则必须写。这跟js、golang都很像。
比如docker需要执行多条命令,使用下面方式。
bash -c 'echo 123;echo 456'
输入、输出
输入、输出符号
输入内容
简单的编辑代码
cat > test.sh <<EOL
echo 123
echo 456
echo 789
EOL
# 没有echo 直接 重定向到文件,效果:清空文件
> backup.sh
# 将输出重定想到文件
exec > 2.txt
管道符号|
一个程序的输出,作为另外一个程序的输入,注意,不是作为,另一个程序的参数。
seq 10|sed 's#^#big#'|while read line;do echo $line" chuangqi";done |cat -n
作为参数时,有两种方案:
xargs
seq 10|xargs echo
seq 10|xargs -n 1 echo
sed/awk… + bash
相当于动态的生成一个shell,然后再去执行。
seq 10|sed 's#^#echo #'|sh
管道,合并错误 |&
grep hello test.txt|&cat -n # 通过-n参数,观测到,通过管道传递给cat
1 grep: test.txt: No such file or directory
短横线
一般习惯将 - 表示,从输入流获取内容。
比如,tar、cat、nc等
在文件末尾追加多行。-表示的输入刘。
cat exa1.txt - > output <<EOF
some lines you want to insert
go here
EOF
-- 缺省
kubectl exec -it qingcloud-844ffd6575-pgjq2 -n qing-cloud -- bash
转义符号 \
如find命令后,exec的参数需要转移。
find . -type d -exec echo {} \;
hello=1
echo $hello
echo \$hello
字符串类的转义
echo -e "hello\nworld"
正则转义