跳转至

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,其中ifelif语句块由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
  • caseesac结尾(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

  • breakcontinue不同于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:从此循环体中断,继续下一循环,类似c
  • continue 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
di An integer, expressed as a decimal number.
o An integer, expressed as an unsigned octal number.
xX 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.
eE 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:字符长度非0
  • STRING:字符长度非0
  • -z STRING:字符长度等于0
  • STRING1 = STRING2:等于
  • STRING1 != STRING2:不等于
  • 数值比较(整数,非浮点数)
  • INTEGER1 -eq INTEGER2:INTEGER1 等于 INTEGER2
  • INTEGER1 -ge INTEGER2:INTEGER1 大于等于 INTEGER2
  • INTEGER1 -gt INTEGER2:INTEGER1 大于 INTEGER2
  • INTEGER1 -le INTEGER2:INTEGER1 小于等于 INTEGER2
  • INTEGER1 -lt INTEGER2:INTEGER1 小于 INTEGER2
  • INTEGER1 -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函数库

  1. 将shell函数写入shell文件中
  2. 在另一个shell文件中或命令行中使用source.将步骤1中的shell函数文件包含进来
  3. 在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 fileexec 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 &