Linux-shell

Shell 脚本的不同运行方式

  • 内建命令不需要创建子进程
  • 内建命令对当前 shell 生效
bash 1.sh
# 不用给1.sh赋予执行权限,bash脚本执行完后会回到当前目录
# 会产生新的子进程

./1.sh
# 必须要可执行权限,bash脚本执行完后会回到当前目录
# 会产生新的子进程

source 1.sh 和 . 1.sh
# 必须要可执行权限,bash脚本执行完后不会回到当前目录
# 不会创建新的子进程

管道与重定向

管道和信号是一样的,也是进程通信的方式之一

# 输入重定向
<

# 输出重定向
>

# 追加模式
>>

# 将a.txt文件内容赋值给变量ss
read ss < a.txt

# 将ss变量内容写入到文件中
echo $ss > a.txt

# 将ss变量内容追加到文件中
echo $ss >> a.txt

# 将错误信息重定向到文件中
xxx 2> a.txt

# 将输出信息全部重定向到文件中
xxx &> a.txt

变量的赋值

  • shell 中不区分变量类型
  • 变量赋值等号两边不允许有空格
  • 将命令的值赋值给变量,使用 $() 和 ``
a=$(ls -l /etc)

变量的作用范围

  • 声明的变量只在当前的 shell 中生效,在子进程、父进程和 bash xx.sh 中都是不生效的,要想使得变量在 bash xx.sh 中生效,需要执行 source xx.sh 或者. xx.sh,因为这两种方式都不会创建新的子进程
  • 使用 export xx,可以使该变量在子进程中可用
  • 使用 unset xx,删除变量

环境变量、预定义变量和位置变量

环境变量每个 shell 打开都可以获取到的变量

  • env 查看环境变量
  • set 查看环境变量、预定义变量和位置变量
  • PATH 该变量定义了命令查找的路径,我们需要添加路径时可以 PATH=$PATH:xx,该变量修改后可以在子进程和别的 shell 中生效,因为被 export 了
  • PS1 设置 shell 中提示

预定义变量

  • $?上一条命令是否执行成功,成功的话返回 0
  • $$ $$
  • $0 当前执行的程序,比如 bash

位置变量(获取命令行参数)

  • $1......$n 特别注意的是当大于等于 10 时,必须写成${10}...${xx}
  • $* 和 $@ 代表所有位置参数
  • $#代表位置参数的数量
  • 如果想给位置变量设置默认值可以用${1-xx},xx 就是设置的默认值

### 环境变量配置文件 #### 所有用户都可用的环境变量保存在
  • /etc/profile
  • /etc/profile.d
  • /etc/bashrc

用户自定义的环境变量

  • ~/.bashrc
  • ~/.bash_profile

数组

定义数组

  • IPTS=(1 2 3 4)

显示所有元素

  • echo ${IPTS[@]}

显示长度

  • echo ${#IPTS[@]}

获取第一个元素

  • echo ${IPTS[0]}

转义与引用

注意单引号 ` 是不对特殊字符进行解释,双引号” 会对特殊字符进行解释

# $a
echo '$a'

# 1
echo "$a"
  • 反引号 ` 可以获取命令执行的结果
num1=`expr 4 + 5`
# 9
echo $num1

运算符

赋值运算符

算数运算符

  • expr 4 + 5 只能支持整数
  • ((4+5))((a=9))((a++))是 let 的简化方式

特殊符号大全

  • $()和反引号``的作用一样,里面包含需要执行的命令
  • ()会创建一个新的 shell
  • []是 test 命令的简写
[[ 5 < 4 ]]
# 1
echo $?
  • {}输出范围和快速操作
# 0 1 2 3 4 5 6 7 8 9
echo {0..9}

# mv 1.sh 1.sh.bakmv 1.sh{,.bak}
  • ;会确保上一条命令执行完在执行下一条
  • &&上一条命令执行成功后执行下一条
  • :类似于 python 中的 pass

test 命令

退出程序命令

  • exit 会返回上一条命令的成功与否
  • exit 10 返回值 10,非 0 则是不正常退出

test 命令可以用来检查文件或者比较值

  • test 可以做一下测试

    • 文件测试
    • 整数比较测试
    • 字符串测试
  • test 测试语句可以简化为 [] 符号
  • [] 还有扩展写法 [[]] 支持 &&、|| 等

if else

if [[ "$1" == "start" ]] ; then
    echo "$0 start..."
elif [[ "$1" == "stop" ]] ; then
    echo "$0 stop..."
else
    echo "Usage: $0 {start|stop}"
fi

case

case "$1" in
    "start" | "START")
        echo "$0 start..."
    ;;

    "stop")
        echo "$0 stop..."
    ;;

    *)
        echo "Usage: $0 {start|stop}"
    ;;
esac

for

#!/bin/bash

for filename in $(ls *.mp3) ; do
    mv $filename $(basename $filename .mp3).mp4
done

for (( i=1; i<=10; i++ )) ; do
    echo $i
done

while

#!/bin/bash

n=1
# [[ $n < 10 ]] 不能用于条件判断
while [  $n -lt 10 ]
do
    echo $n
    ((n++))

done

嵌套

#!/bin/bash

for filename in $(ls *.mp4) ; do
    if [ -x $filename ]; then
        echo $filename ; break
    fi
done

循环处理位置参数

  • $#  位置参数的数量
  • $*  所有的位置参数
  • $0  脚本名称
#!/bin/bash

# for
for args in $* ; do
    if [ "$args" = "help" ] ; then
        echo "$args" "$args"
    fi
done

# while
while [ "$#" -ge 1 ] ; do
    if [ "$1" = "help" ] ; then
        echo "$1" "$1"
    fi
    shift
done

自定义函数

  • local  声明函数内的变量
#!/bin/bash

function checkpid() {
    local i

    for i in $* ; do
        [ -d "/proc/$i" ] && return 0
    done

    return 1
}

脚本控制

fork 炸弹 - .(){.|.&};.

普通用户创建的线程数是受到控制的,可以通过 ulimit -a 控制

捕获信号

# kill -l
1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX

trap 捕获信号

#!/bin/bash

trap "echo 15" 15

echo $$

while : ; do
    :
done

计划任务

一次性的计划任务:at 命令

  • 没有标准输出,需要使用重定向
  • 在 at 命令中执行的 shell 命令如果不是系统内置命令,需要使用命令的完整路径
at 18:31 (在18点31执行任务,ctrl + d退出)
atq (显示一次性任务的列表)

周期性计划任务(同一次性任务有标准输出流和命令路径的问题)

  • /var/log/cron 任务的日志
  • /var/spool/cron 用户的计划任务
  • 配置方式 crontabl -e
  • 查看现有的计划任务 crontab -l
  • 配置方式: 分钟 小时 日期 月份 星期 执行的命令

    • 比如 1 1 1 1 1-5 echo crontab (1 月 1 日 1 时 1 分 如果是周一到周五,就输出 crontab)

计划任务加锁

延时计划任务即使系统遇到了关机等影响计划任务的事情,也能让计划任务延时运行起来

  • /etc/cron.d/0hourly 系统记录计划任务的是否运行(每小时)
  • /etc/anacrontab 延时任务文件夹 (每天、每周、每月)

flock -xn "tmp/f.lock" -c "/root/a.sh" 一段时间只能运行一个脚本

  • /tmp/f.lock 锁存放的文件路径
  • 需要锁住的命令/root/a.sh
# 加锁
flock -xn "/tmp/f.lock" -c "/tmp/1.sh"

# 另外一个地方执行该脚本时就会直接退出
flock -xn "/tmp/f.lock" -c "/tmp/1.sh"

Published under  on .

pipihua

我是皮皮花,一个前后端通吃的前端攻城狮,如果感觉不错欢迎点击小心心♥(ˆ◡ˆԅ) star on GitHub!