Shell 学习笔记-提高篇

Shell 学习笔记-提高篇

学习教程

LearnShell

学习内容

特殊变量

  • $0:当前脚本文件
  • $n:传入脚本或者语法参数的第几个数
  • $#:传入脚本或者语法参数的个数
  • $@:所有传入脚本和 函数的参数
  • $*:所有传入脚本和 函数的参数
  • $?: 上一条命令的执行状态码
  • $$:当前 shell 的 process id
  • $!: Shell 最后运行的后台 Process 的 PID
$@,$*在双引号引用下表现不一样,$*会变为一个整体
  • ‘’:单引号,不具有变量置换的功能
  • “”:双引号,具有变量置换的功能
  • ():在中间的为子 shell 的起始与结束
  • {}:在中间为命令块的组合

trap 命令

trap命令用于指定在接收到信号后将要采取的动作,常见的用途是在脚本程序被中断时完成清理工作。当 shell 接收到 sigspec 指定的信号时,arg 参数(命令)将会被读取,并被执行

  • SIGINT 中断信号(Ctrl + C:2)
  • SIGQUIT 退出信号(Ctrl +\:2)
  • SIGFE 算术错误
#!/bin/bash

# traptest.sh
# notice you cannot make Ctrl-C work in this shell,
# try with your local one, also remeber to chmod +x
# your local .sh file so you can execute it!

trap "echo Booh!" SIGINT SIGTERM
echo "it's going to run until you hit Ctrl+Z"
echo "hit Ctrl+C to be blown away!"

while true
do
    sleep 60
done

文件测试

  • 测试文件是否存在
#!/bin/bash
filename="sample.md"
if [ -e "$filename" ]; then
    echo "$filename exists as a file"
fi
  • 测试文件目录是否存在
#!/bin/bash
directory_name="test_directory"
if [ -d "$directory_name" ]; then
    echo "$directory_name exists as a directory"
fi

- 测试是否可读

#!/bin/bash
filename="sample.md"
if [ ! -f "$filename" ]; then
    touch "$filename"
fi
if [ -r "$filename" ]; then
    echo "you are allowed to read $filename"
else
    echo "you are not allowed to read $filename"
fi

命令行选项解析

getopt

#!/bin/bash

while getopts "a:bc" arg
do
        case $arg in
             a)
                echo "a's arg:$OPTARG"
                ;;
             b)
                echo "b"
                ;;
             c)
                echo "c"
                ;;
             ?)  #当有不认识的选项的时候arg为?
            echo "unkonw argument"
        exit 1
        ;;
        esac
done
  • 只支持短选项
  • 选项后面的冒号表示该选项需要参数,且参数存在$OPTARG 中
  • OPTIND:代表当前选项在参数列表中的位移
  • shift $(($OPTIND - 1)) 取选项之后的参数

getopt

#!/bin/bash
#-o表示短选项,两个冒号表示该选项有一个可选参数,可选参数必须紧贴选项
#如-carg 而不能是-c arg
#--long表示长选项
#"$@"在上面解释过
# -n:出错时的信息
# -- :举一个例子比较好理解:
#我们要创建一个名字为 "-f"的目录你会怎么办?
# mkdir -f #不成功,因为-f会被mkdir当作选项来解析,这时就可以使用
# mkdir -- -f 这样-f就不会被作为选项。

TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
     -n 'example.bash' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
#set 会重新排列参数的顺序,也就是改变$1,$2...$n的值,这些值在getopt中重新排列过了
eval set -- "$TEMP"

#经过getopt的处理,下面处理具体选项。

while true ; do
        case "$1" in
                -a|--a-long) echo "Option a" ; shift ;;
                -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
                -c|--c-long)
                        # c has an optional argument. As we are in quoted mode,
                        # an empty parameter will be generated if its optional
                        # argument is not found.
                        case "$2" in
                                "") echo "Option c, no argument"; shift 2 ;;
                                *)  echo "Option c, argument \`$2'" ; shift 2 ;;
                        esac ;;
                --) shift ; break ;;
                *) echo "Internal error!" ; exit 1 ;;
        esac
done
echo "Remaining arguments:"
for arg do
   echo '--> '"\`$arg'" ;
done
getops 命令的不足:
  • 选项参数的格式必须是-d val,而不能是中间没有空格的-dval。
  • 所有选项参数必须写在其它参数的前面,因为 getopts 是从命令行前面开始处理,遇到非-开头的参数,或者选项参数结束标记--就中止了,如果中间遇到非选项的命令行参数,后面的选项参数就都取不到了。
  • 不支持长选项, 也就是--debug 之类的选项

Process Substitution

  • 输出 重定向 >
$ who > users.out
  • 追加模式输出 重定向 >>
$ ls >> users.out
  • 输入 重定向 <
$ wc -l < users.out

深入重定向

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

  • 标准输入文件(stdin):stdin 的文件描述符为 0,Unix 程序默认从 stdin 读取数据。
  • 标准输出文件(stdout):stdout 的文件描述符为 1,Unix 程序默认向 stdout 输出数据。
  • 标准错误文件(stderr):stderr 的文件描述符为 2,Unix 程序会向 stderr 流中写入错误信息。
  • 如果希望 stderr 重定向到 file,可以这样写
command 2 > file
  • 如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写
command > file 2>&1
放在>后面的&,表示重定向的目标不是一个文件,而是一个文件描述符
n >& m 将输出文件 m 和 n 合并。
n <& m 将输入文件 m 和 n 合并
  • 如果希望对 stdin 和 stdout 都重定向,可以这样写:
command < file1 >file2
  • Here Document
wc -l << EOF
heredoc> mmb
heredoc> learn
heredoc> note
heredoc> shell
heredoc> EOF
       4
  • 禁止输出
ls > /dev/null

正则表达式

BRE:基本正则表达式

  • 完全匹配 mumubin
grep -n mumubin *.sh
  • mumubin 作为行的开头
grep -n ^mumubin *.sh
  • mumubin 作为行的结尾
grep -n mumubin$ *.sh
  • 这一行完全 为 mumubin,没有其它字符
grep -n ^mumubin$ *.sh
  • 完全匹配 mumubin 或者 Mumubin
grep -n "[mM]umubin" *.sh
  • 匹配 mumu 和 bin,中间是任意 一个字符
grep -n mumu.bin *.sh
  • 匹配 mumu 和 bin,中间是任意 0 个活多个字符
grep -n "mumu.*bin" *.sh
^:匹配行首位置
$:匹配行尾位置
.:匹配任意祖父
*:对*之前的匹配整体或字符匹配任意次(包括 0 次)
?:对?之前的匹配整体或字符匹配 0 次或 1 次
{n}: 对n之前的匹配整体或字符匹配 n 次
{m,}: 对{ 之前的匹配整体或字符匹配至少 m 次
{m,n}: 对{ 之前的匹配整体或字符匹配 m 到 n 次
[abcdef]: 对单字符而言匹配[]中的字符
[a-z]: 对单字符而言,匹配任意一个小写字母
[^a-z]:不匹配括号中的内容
|:匹配左右两边任意一项

相关推荐