shell教程¶
1.1 set参数设置¶
set -u
:如果有不存在的变量,打印错误信息,并退出set -x
:在执行命令前,打印执行的命令set +x
:取消set -x
的效果set -e
:如果命令执行错误,打印错误信息,并退出(不适合管道)set -o pipefail
:对set -e
的补充,管道命令执行错误,打印报错信息,并退出
以上命令可以整合一起写,如set -uxe
1.2 exit 设置退出码¶
脚本默认退出码是最后一个shell指令执行结果,可以使用exit 退出脚本并返回退出码。 - 示例
echo hello
exit 0
1.3 变量和常量¶
命名规范:常量全大写,变量小写
- 常量:readonly
+常量名
- 删除变量:unset
+变量名(不能删除常量)
- 读变量:
- ${变量名}
- $变量名
- 修改变量值:变量名=变量新值
#!/bin/bash
# 变量
str="hello world!"
echo ${str}
# 常量
readonly IVALUE=10
echo "常量"${IVALUE}
# 取消变量
unset str
echo ${str}
1.3.1 局部变量¶
- 局部变量用
local
标识,一般用于函数
hello() {
local str="hello"
echo $str
}
hello
echo "\$str=$str"
1.3.2 变量替换¶
${var:-word}
如果变量 var 为空或已被删除(unset),那么返回 word,但不改变 var的值。${var:=word}
如果变量 var 为空或已被删除(unset),那么返回 word,并将 var 的值设置为 word。${var:?message}
如果变量 var 为空或已被删除(unset),那么将消息 message 送到标准错误输出,可以用来检测变量 var 是否可以被正常赋值。若此替换出现在Shell脚本中,那么脚本将停止运行。${var:+word}
如果变量 var 被定义,那么返回 word,但不改变 var 的值。
$ echo ${val:-hello};echo $val
hello
$ echo ${val:=hello};echo $val
hello
hello
$ echo ${val:+world};echo $val
world
hello
1.3.3 特殊变量($$ $1 $* $@ $# $?)
¶
#!/bin/bash
# 特殊变量
echo "\$0脚本名 "$0
echo "\$$脚本进程ID "$$
echo "\$n脚本第n个参数,\$1脚本第一个参数 "$1
echo "\$#脚本参数个数"$#
echo "\$*脚本所有参数 "$*
echo "\$@脚本所有参数 "$@
echo "\$?上一个脚本执行结果"$?
当$*
被双引号包裹时,将是一个整体,这时与$@
有点不同
#!/bin/bash
# test.sh
for val in "$@"
do
echo val
done
for val in "$*"
do
echo val
done
执行脚本结果如下$*
被当成一个整体被输出
$ ./test.sh 1 2 3 4 5
1
2
3
4
5
1 2 3 4 5
1.4 {}的使用¶
1.4.1 {val1,val2,...,valn}用法¶
- 功能:展开集合中列出的元素
$ echo file{1,2,3}
file1 file2 file3
1.4.2 {start..end..step}用法¶
- 功能:展开集合范围中元素,并且可以指定步长
$ echo file{0..3}
file0 file1 file2 file3
$ echo {0..10..2}
0 2 4 6 8 10
- 通常用于for in循环中
$ for i in {0..5};do echo file$i ;done
file0
file1
file2
file3
file4
file5
1.5 特殊符号使用¶
1.5.1 $()、``读取命令结果¶
$()
和``都是用来执行命令后提取执行结果到变量中。- 示例
$ a=`echo "hello"`
$ echo $a
hello
$ b=$(echo "hello")
$ echo $b
hello
1.5.2 ${ }¶
${var}
可以获取变量的值,作用同$var
。此时${var}
相较于$var
的好处时可以明确变量名var的界限- 示例:下面示例由于变量名被认为是bb,导致解析结果错误
$ b="hello"
[here4@web17 bin]$ echo $bb
[here4@web17 bin]$ echo ${b}
hello
${}
更高级的用法是用于字符串的操作,比如截取子串。${var:1:3}
1.5.3 $[]
和$(())¶
$[]
和$(())
都可以用来计算+-*/%
,但只能计算整数。一般推荐使用后者- 示例
$ echo $[1+4/2]
3
$ echo $((1+4/2))
3
1.6 运算符¶
1.6.1 算术运算符¶
- 整形计算:利用
((表达式))
语法计算,或者使用linux上安装的可执行计算文件,如expr
- 浮点运算:使用
bc
计算 scale
指定精度,如scale=6
,代表保留小数点后6位
#!/bin/bash
#算术运算
##整形运算
a=$((1 + 2))
((b = 1 + 2))
echo "a=\$((1+2)),a=$a"
echo "((b=1+2))=$b"
##浮点型运算 使用echo+管道给bc传表达式
echo "scale=6;3.12*4.65/3" | bc
a=$(echo "scale=6;3.12*4.65/3" | bc)
echo $a
1.6.2 关系运算符¶
- 使用
[]
或[[]]
([]
即test指令的符号表示,[[]]
是[]
的加强版) - 表达式与
[]
之间要空格隔开 - 比较符如
-lt -ge
需要与比较数用空格隔开 []
也可以测试文件属性,具体请看test
文档
#!/bin/bash
#关系运算
##整形数值比较
a=1
b=3
if [ $a -lt $b ]; then
echo "$a<$b=true"
else
echo "$a<$b=false"
fi
##字符串比较
str1="hello"
str2="world"
if [ $str1 != $str2 ]; then
echo "$str1!=$str2=true"
else
echo "$str1!=$str2=false"
fi
## bool运算符-a且,-o或,!非
if [ $a -lt $b -a $str1 != $str2 ]; then
echo "$a -lt $b -a $str1 != $str2 条件全真"
else
echo "非全真"
fi
1.7 字符串¶
1.7.1 字符串3种表达形式¶
变量名=str
:字符串不用引号包裹- 不被引号包围的字符串中出现变量时也会被解析,这一点和双引号" "包围的字符串一样。
- 字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。
变量名='str'
:字符串用单引号包裹- 任何字符都会原样输出,在其中使用变量是无效的。
- 字符串中不能出现单引号,即使对单引号进行转义也不行。
变量名="str"
:字符串用双引号包裹- 如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出。
- 字符串中可以出现双引号,只要它被转义了就行。
- 示例
# 脚本文件 str.sh
url=https://www.baidu.com/index.html
echo "url:$url"
echo 'url:$url'
echo url:$url
# 执行结果
$ sh str.sh
url:https://www.baidu.com/index.html
url:$url
url:https://www.baidu.com/index.html
https://blog.csdn.net/ITlinuxP/article/details/79060822
1.7.2 字符串长度¶
- 语法:
${#words}
- 示例
$ echo $url
https://www.baidu.com/index.html
$ echo ${#url}
32
1.7.3 字符串拼接¶
语法形式:将字符串紧密相连(中间不留空格),或者用双引号包裹(可以用空格) - 示例:下例中p3变量赋值中str1和str2中间有个空格,导致str2被解析成命令
$ cat -n str.sh
1 str1=hello
2 str2=world
3
4 p1=$str1$str2
5 p2="$str1 str2"
6 p3=$str1 $str2
7
8 echo $p1
9 echo $p2
10 echo $p3
$ sh vim.txt
vim.txt: line 6: world: command not found
helloworld
hello str2
1.7.4 指定位置和数量截取¶
- 语法:
0-
是前缀是指从右往左数位置 ${words:num_start:num_end}
:从第num_start个字符开始截取num_end个字符${words:num_start}
:从第num_start个字符开始截取到最后一个字符${words:0-num_start:num_end}
:从倒数第num_start个字符开始截取num_end个字符${words:0-num_start}
:从倒数第num_start个字符开始截取到最后一个字符- 示例
$ echo $url
https://www.baidu.com/index.html
$ echo ${url:8:3}
www
$ echo ${url:8}
www.baidu.com/index.html
$ echo ${url:0-8:3}
dex
$ echo ${url:0-8}
dex.html
1.7.5 匹配字符串截取¶
1.7.5.1 从左往右查找¶
注意:#
表示从左往右模式,其中*
表示通配符
- 语法:
- ${str#substr}
:匹配以substr
开头的字符串,再截取substr后到结尾的字符串
- ${str#*substr}
:匹配第一次出现substr
的字符串,再截取substr后到结尾的字符串
- ${str##*substr}
:匹配最后一次出现substr
的字符串,再截取substr后到结尾的字符串
- 示例
$ echo ${url}
https://www.baidu.com/index.html
$ echo ${url#https}
://www.baidu.com/index.html
$ echo ${url#*/}
/www.baidu.com/index.html
$ echo ${url##*/}
index.html
1.7.5.2 从右往左查找¶
注意:%
表示从左往右模式,其中*
表示通配符
- 功能:从words1中查找首次出现words2后的字符到结尾字符
- 示例
${#str}
和${str:1:3}
分别求字符串长度和截取字符串子串test
也可以操作字符串,功能更多
#!/bin/bash
#字符串操作
str="hello"
echo "${str}长度=${#str}"
echo "${str}从索引1开始3字符串=${str:1:3}"
echo "${str}从索引1开始子串=${str:1}"
1.8 数组¶
数组索引从0开始
- 数组赋值
- array=(val1 val2 ... valn)
- array=([index1]=val1 [index2]=val2 [index3]=val3)
:index可以不是连续的,比如:ages=([3]=24 [5]=19 [10]=12)
- array[0]=val1;array[1]=val2;...;array[n-1]=valn
- 注意事项:数组值之间用空格隔开
- 数组大小
- ${#array[@]}
- ${#array[*]}
- 数组全部数据
- ${array[@]}
- ${array[*]}
- 某一索引数据
- ${array[0]}
#!/bin/bash
set -xeu
# 数组
array1=(1 2 3 4 5)
echo ${#array1[@]}
echo "${array1[3]}"
echo "${array1[*]}"
echo "${array1[@]}"
array2=(
1
2
3
4
5
)
array3[0]=1
array3[3]=4
array3[4]=5
echo "${#array3[*]}"
echo "${array3[0]}"
echo "${array3[1]}"
1.9 条件语句¶
1.9.1 if条件语句¶
if...then...elif...then...else...fi
,其中if
和elif
语句块由then
引导
#!/bin/bash
str="hello"
if [[ -z $str ]]; then
echo "$str为空"
elif [[ $str = "hello" ]]; then
echo "${str}=hello"
else
echo "$str非空"
fi
1.9.2 case条件语句¶
case...in...esac
case
由esac
结尾(case反序)- 每一个条件的语句块
;;
结束
#!/bin/bash
printf "请输入数字1—4\n"
# -e 开启转义
echo -e '你输入的数字是:\c'
read -r NUMBER
case $NUMBER in
1)
echo "你输入的数字是1"
;;
2)
echo "你输入的数字是2"
;;
3)
echo "你输入的数字是3"
;;
4)
echo "你输入的数字是4"
;;
*)
echo "请输入正确数字,你输入的是$NUMBER"
;;
esac
1.10 循环¶
break
:跳出整个循环体(参考c,java等语言)continue
:跳出当前循环,继续下一循环(参考c,java等语言)
1.10.1 for 循环¶
for ((i = 0; i < 10; i++));do ... done
#!/bin/bash
array=(
1
2
3
4
5
)
for ((i = 0; i < ${#array[*]}; i++)); do
echo "${array[i]}"
done
1.10.2 for in循环¶
for ... in ... do ... done
#!/bin/bash
array=(
1
2
3
4
5
)
echo "循环数组"
for i in ${array[*]}; do
echo "$i"
done
for i in 1 2 3 4 5; do
echo "$i"
done
echo "打印当前路径下文件名"
i=0
for fl in ./*; do
echo "文件$((++i))$fl"
done
if [[ $# -gt 0 ]]; then
echo "你输入参数如下:"
for i in "$@"; do
echo "$i"
done
else
echo "你没有输入任意参数"
fi
1.10.3 while循环¶
while command do ... done
,与c中while
一样,当条件假时退出循环
#!/bin/bash
echo -e "请输入任意整形值,输入0结束:\c"
while read -r NUM; do
echo "你输入了$NUM"
if [ $NUM -eq 0 ]; then
echo "退出shell"
#或者exit 0
break
fi
done
1.10.4 until循环¶
until command do ... done
,与c中do while
一样,当条件真时退出循环
#!/bin/bash
a=0
b=4
until [ $((++a)) -gt $b ]; do
echo "$a <= $b"
done
1.11 break和continue¶
break
和continue
不同于c语言,可以指定跳出那一层循环,其中continue n+1
等价于break n
,跳出第n层循环。(n的含义是从当前循环层从里往外数,第几层,当前层为1)
1.11.1 break¶
break n
:跳出第n层循环,如空3层循环,2表示跳出第2层循环,3表示跳出最外层循环,1表示跳出当前层循环,默认n就是1
#!/bin/bash
#跳出循环break
for i in 0 1 2; do
if [ $i -gt 1 ]; then
break
else
echo $i
fi
done
#跳出任意层循环 break n
for z in 0 1 2; do
for i in 0 1 2; do
for j in 0 1 2 3 4; do
if [ $i -eq 1 ] && [ $j -eq 3 ]; then
break 2
else
echo "$z $i $j"
fi
done
done
done
1.11.2 continue¶
continue
:从此循环体中断,继续下一循环,类似ccontinue n
:继续到第n层循环,类似break (n-1;n>1)
#!/bin/bash
#继续下一循环
for i in 0 1 2; do
if [ $i -eq 1 ]; then
continue
else
echo $i
fi
done
#继续到任意层循环 continue n
for z in 0 1 2 3 4; do
for i in 0 1 2 3 4; do
for j in 0 1 2 3 4; do
if [ $z -eq $i ] && [ $i -eq $j ]; then
echo "$z $i $j全等继续最外层循环"
continue 3
else
echo "$z $i $j"
fi
done
done
done
1.12 printf¶
- 语法:
%[-wide.precision]转换字符
-
:左对齐wide
:字符所占的总宽度,大于字符宽度用空格补齐;比如字符占11位,wide为15位,则输入字符占15位precision
:在字符类型中表示能截取的最大字符数;在浮点类型数值中表示精度(小数点后多少位)- 转换字符:比如d表示整形,s表示字符串,f表示浮点型
- 规则:必须以%开头,尾部必须要转换字符(d、s、l等)
$ printf "%-20.5s" "hello world"
hello $
$ printf "%-20.5f" 123545.6568486849
123545.65685 $
conversion character | argument type |
---|---|
d, i | An integer, expressed as a decimal number. |
o | An integer, expressed as an unsigned octal number. |
x, X | An integer, expressed as an unsigned hexadecimal number |
u | An integer, expressed as an unsigned decimal number. |
c | An integer, expressed as a character. The integer corresponds to the character's ASCII code. |
s | A string. |
f | A floating-point number, with a default precision of 6. |
e, E | A floating-point number expressed in scientific notation, with a default precision of 6. |
p | A memory address pointer. |
% | No conversion; a literal percent sign ("%") is printed instead. |
1.13 read¶
- 功能:读取用户输入
- 语法:
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
-a
后跟一个变量,该变量会被认为是个数组,然后给其赋值,默认是以空格为分割符。-d
后面跟一个标志符,其实只有其后的第一个字符有用,作为结束的标志。-p
后面跟提示信息,即在输入前打印提示信息。-e
在输入的时候可以使用命令补全功能。(仅提示当前目录下已有的文件或目录名)-n
后跟一个数字,定义输入文本的长度。(达到字符限制自动提交)-r
屏蔽\,如果没有该选项,则\作为一个转义字符,有的话 \就是个正常的字符了。-s
安静模式,在输入字符时不再屏幕上显示,例如login时输入密码。-t
后面跟秒数,定义输入字符的等待时间。-u
后面跟fd,从文件描述符中读入,该文件描述符可以是exec新开启的- 示例
# 1........
echo "输入一个值"
read value
echo "你输入的是:$value"
# 输出结果如下.....
#输入一个值
#\123
#你输入的是:123
# 2........
echo "输入一个值"
read -r value
echo "你输入的是:$value"
# 输出结果如下.....
#输入一个值
#\123
#你输入的是:\123
# 3........
read -p "输入一个值:" value
echo "你输入的是:$value"
# 输出结果如下.....
#输入一个值:123
#你输入的是:123
1.13.1 密码模式¶
- 示例
#!/bin/bash
read -s -p "请输入您的密码:" pass
printf "\n您输入的密码是 %s \n" "$pass"
# 输出结果如下.....
#请输入您的密码:
#您输入的密码是 123456
1.13.2 读取文件¶
- 示例
#!/bin/bash
count=1 # 赋值语句,不加空格
cat test.txt | while read line # cat 命令的输出作为read命令的输入,read读到的值放在line中
do
echo "Line $count:$line"
count=$[ $count + 1 ] # 注意中括号中的空格。
done
echo "finish"
exit 0
1.14 select¶
- 功能:select用来展示一系列选项供用户选择
- 示例
#!/bin/bash
select i in mon tue wed exit
do
case $i in
mon) echo "Monday";;
tue) echo "Tuesday";;
wed) echo "Wednesday";;
exit) exit;;
esac
done
- 结果
$ ./test.sh
1) mon
2) tue
3) wed
4) exit
#? 1
Monday
#? 2
Tuesday
#? 3
Wednesday
#? 4
1.15 getopt¶
强烈建议使用getopt,而不是getops
1.16 getopts¶
- 功能:解析传入shell脚本的参数
- 语法:
getopts optstring name
optstring
:可选字符,格式有2种,一种只含选项;另一种选项+值,这种需要在可选参数后加上冒号:
"v"
:解析参数-v
"v:"
:解析参数-v value
,选项后接值数据。这个value值会被放入OTPARG变量中
name
:当解析到了optstring
指定的选项后,会将选项值放入name
变量中,name
变量名称任取;当解析失败时,会将问号?
放入name
变量中。
1.16.1 变量OPTARG、OPTIND¶
- `OPTIND`表示的是下一个选项参数的位置,不是当前选项参数的位置。
- `getops`会根据`OPTIND`来解析哪一个位置的参数,因此,不要去主动修改`OPTIND`的值。当然,如果想要在多个地方调用getops时,可以主动修改OPTIND变量值。
- `OPTARG`只在解析参数选项时,提取值到另一个变量中保存。解析完后这个OPTARG变量数据会清空
- `OPTIND`会保留最后一个参数索引,整个shell生命周期都存在
OPTARG
:解析带选项值的参数时,选项后面的值放入这个变量中OPTIND
:表示下一个选项参数的索引。(默认值是1,当选项带值的,也是显现选项所在的位置)- 示例
$ cat test.sh
echo "start:$OPTIND"
while getopts "a:bc" opt
do
case $opt in
a)
echo "a 选项:$OPTIND $OPTARG"
;;
b)
echo "b 选项:$OPTIND $OPTARG"
;;
c)
echo "c 选项:$OPTIND $OPTARG"
;;
?)
echo "参数解析失败"
;;
esac
done
echo "end:$OPTIND $OPTARG"
$ sh test.sh -c -a hello
start:1
c 选项:2
a 选项:4 hello
end:4
$ sh test.sh -g
11.sh: illegal option -- g
参数解析失败
1.17 shift¶
- 功能:将shell脚本参数向左移动多少位,左边的参数会被移除
- 语法:
shift [n]
- 示例
$ cat test.sh
echo "start:参数总数$#"
shift 2
echo "shift:参数总数$#"
for arg in "$@"
do
echo $arg
done
$ sh test.sh 1 2 3 4
start:参数总数4
shift:参数总数2
3
4
1.18 test 测试条件¶
1.18.1 (())提供高级算术运算¶
(())
运算支持所有c语言定义的运算,且不要求空格分割- 语法形式:
((expr))
:计算表达式内容$((expr))
:取表达式计算结果- 示例
#!/bin/bash
a=$((b=1+2))
echo "a=$a b=$b"
c=$((10%3))
echo "c=$c"
d=$((a>c?1:0))
echo "d=$d"
- 输出结果
a=3 b=3
a=4
c=1
d=1
1.18.2 []提供简单的数值比较、字符串比较、文件比较¶
- 比较运算符
( EXPRESSION )
:EXPRESSION is true! EXPRESSION
:非运算EXPRESSION1 -a EXPRESSION2
:且运算EXPRESSION1 -o EXPRESSION2
:或运算- 字符比较
-n STRING
:字符长度非0STRING
:字符长度非0-z STRING
:字符长度等于0STRING1 = STRING2
:等于STRING1 != STRING2
:不等于- 数值比较(整数,非浮点数)
INTEGER1 -eq INTEGER2
:INTEGER1 等于 INTEGER2INTEGER1 -ge INTEGER2
:INTEGER1 大于等于 INTEGER2INTEGER1 -gt INTEGER2
:INTEGER1 大于 INTEGER2INTEGER1 -le INTEGER2
:INTEGER1 小于等于 INTEGER2INTEGER1 -lt INTEGER2
:INTEGER1 小于 INTEGER2INTEGER1 -ne INTEGER2
:INTEGER1 不等于 INTEGER2- 文件比较
FILE1 -nt FILE2
:FILE1 比 FILE2 新(mtime)FILE1 -ot FILE2
:FILE1 比 FILE2 旧(mtime)-d FILE
:文件存在且是目录-e FILE
:文件存在-f FILE
:文件存在且是一个常规文件-s FILE
:文件存在且文件大小大于0-r FILE
:文件存在且具有可读权限-w FILE
:文件存在且具有可写权限-x FILE
:文件存在且具有可执行权限
1.18.3 [[]]提供了针对字符串模式匹配功能¶
- 双中括号是单中括号的扩展版,支持更多运算符
- 比较运算符
&&
:||
:!=
:=
或==
:<
:>
:
1.19 函数¶
- 函数
()
中不能有形参,但函数内部可通过$1 $2 ... $9 ${10} ... ${n}
获取参数,当参数多余10个时,参数要由${n}
而不是$n
获取 - 调用函数不需要带
()
,传参接着函数名后写,如:fun_name 1 2 "3"
,表示调用函数fun_name并且传给函数3个参数 - 函数中也能使用
return
,但只能返回整形数值,如:return 2
,能不能return "2"
function
标识可有可无,如function add(){}
等价于add(){}
#!/bin/bash
add() {
#计算参数总和
all=0
for i in "$@"; do
all=$((all + i))
done
return $all
}
add 1 2 3 4
#$?获取上一指令结果,此处为add函数返回值
echo "函数add 1 2 3 4返回值:$?"
1.20 扩展进阶¶
1.20.1 包含其它shell文件¶
包含文件类似于c语言中的include,可以将外部脚本合并到当前脚本文件中
- 方式一:. file.sh
,其中.
与文件名间有一空格
- 方式二:source file.sh
#!/bin/bash
. ./str.sh
# 使用str.sh中定义的str
echo "$str"
source ./function.sh
1.20.2 制作并使用shell函数库¶
- 将shell函数写入shell文件中
- 在另一个shell文件中或命令行中使用
source
或.
将步骤1中的shell函数文件包含进来 - 在shell文件中或命令行中使用函数
1.20.3 交互式输入的自动化¶
- 使用场景:在自动化安装(一键安装)中,不能使用交互式来读取输入值,这时可以使用以下方式来处理
1.20.3.1 使用echo+管道方式¶
- 示例
$ cat test.sh
echo "开始交互式输入"
echo "选择1:Y/N:"
read opt1
echo "选择2:Y/N:"
read opt2
echo "选择3:Y/N:"
read opt3
echo "opt1:$opt1 opt2:$opt2 opt3:$opt3"
$ echo -e "Y\nY\nN"|sh 11.sh
选择1:Y/N:
选择2:Y/N:
选择3:Y/N:
opt1:Y opt2:Y opt3:N
1.20.3.2 使用文件重定向方式¶
- 示例
$ cat opt.txt
Y
N
Y
$ sh 11.sh <opt.txt
开始交互式输入
选择1:Y/N:
选择2:Y/N:
选择3:Y/N:
opt1:Y opt2:N opt3:Y
1.20.4 脚本执行方式与是否产生子shell的关系¶
`source file`取脚本里面的语句依次在当前shell里面执行,没有建立新的子shell
- 参考博客
$(commond)
、bash shellfile
、./filename
:会产生新的子shell,子shell继承父shell的一切环境变量、已打开的文件标识符、当前工作目录等。子shell的修改不影响父shell。source file
、exec file
:不会产生子shell
1.20.5 子shell导致局部变量¶
- 参考
- 方法一:
shopt -s lastpipe
在bash4.2+版本上支持
#!/usr/bin/env bash
shopt -s lastpipe
n=0
printf "%s\n" {1..10} | while read i; do (( n+=i )); done
echo $n
- 方法二:使用重定向+EOF技术
n=0
SUMMANDS="$(printf '%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n' 1 2 3 4 5 6 7 8 9 10)"
while read i; do n=$(( n + i )); done <<SUMMANDS_INPUT
$SUMMANDS
SUMMANDS_INPUT
echo $n
- 示例2
[root@centos7 ~]# while read v1 v2;do echo "$v1 $v2";done<<end
> 1
> 2
> end
1
2
1.21 nohup重定向日志清空问题¶
- 现象:当使用
nohup ./test.sh > ./test.log 2>&1 &
,会生成test.log文件,然后我们在脚本文件test.sh中执行清空文件指令,如cp /dev/null ./test.log
或> ./test.log
时,发现test.log文件大小依然没有降低,但test.log文件中只有新增的日志。 - 解决:使用追加方式写入到日志文件中,如:
nohup ./test.sh >> ./test.log 2>&1 &