前言: shell脚本的使用几乎无处不在,故记录一下平常使用的案例,以作备忘
案例一
1.需求
当前目录文件夹结构如下,需要找到内容不是"native:vendor"的link_type文件,并且用tree命令显示找到文件所在文件夹的结构(只显示文件夹,不显示文件)
2.源码
#!/bin/bash
for LINK_TYPE_PATH in $(find -name "link_type")
do
LINK_TYPE=$(cat $LINK_TYPE_PATH)
if [ "$LINK_TYPE" != "native:vendor" ]; then
LINK_TYPE_DIR=$(echo $LINK_TYPE_PATH | sed -e s:"/link_type$":"":g) #sed将尾部的"/link_type"替换为空
$(ls -a $LINK_TYPE_DIR | grep ".*/")
for ELEMENT in $(ls $LINK_TYPE_DIR)
do
SUB_DIR_OR_FILE=$LINK_TYPE_DIR"/"$ELEMENT
if [ -d $SUB_DIR_OR_FILE ]; then #说明1
echo "\033[31;40mLINK_TYPE: [ "$LINK_TYPE" ]\033[0m" #说明2
tree -d -L 2 $LINK_TYPE_DIR #"-d"代表只显示文件夹,"-L 2"代表显示2层文件夹结构
echo ""
break
fi
done
fi
done
说明1:
选项 | 说明 |
---|---|
if [ -a 文件路径 ] | 如果文件存在,等同于-b/-c/-f的集合,不能取反 |
if [ -b 文件路径 ] | 如果文件存在且是一个块设备文件 |
if [ -c 文件路径 ] | 如果文件存在且是一个字符型设备文件 |
if [ -d 文件路径 ] | 如果文件夹存在 |
if [ -e 文件路径 ] | 类似于-a选项,可以进行取反"if [ ! -e 文件路径 ]",表示如果不存在 |
if [ -f 文件路径 ] | 如果文件存在且是一个普通文件 |
if [ -n 文件路径 ] | 如果字符串非空,和"if [ 字符串 ]"一样 |
if [ -r 文件路径 ] | 如果文件存在且可读 |
if [ -s 文件路径 ] | 如果文件存在且不为空时真 |
if [ -w 文件路径 ] | 如果文件存在且可写 |
if [ -x 文件路径 ] | 如果文件存在且可执行 |
if [ -z 文件路径 ] | 如果字符串为空 |
说明2:
字段"\033[31;40m***\033[0m"是用来设置文字的前景色和背景色的,其中
(1) "\033"代表使用转义序列;
(2) "["代表转义序列的开始;
(3) "31(前景红色)"和"40(背景黑色)"是颜色的代号,30-37代表前景色,40-47代表背景色;
(4) "m"针对字体的转义需要加此项;
(5) "***“是要输出的字符串;
(6) 最后结尾”\033[0m"代表对字符串的转义结束;
(7) 其他转义功能如下:
\33[nA 光标上移n行 \33[0m 关闭所有属性
\33[nB 光标下移n行 \33[1m 设置高亮度
\33[nC 光标右移n行 \33[4m 下划线
\33[nD 光标左移n行 \33[5m 闪烁
\33[y;xH 设置光标位置 \33[7m 反显
\33[s 保存光标位置 \33[8m 消隐
\33[u 恢复光标位置 \33[30m — \33[37m 设置前景色
\33[K 清除从光标到行尾的内容 \33[40m — \33[47m 设置背景色
\33[?25l 隐藏光标
\33[?25h 显示光标
\33[2J 清屏
3. 运行结果
案例二
1. 背景
pyenv工具中有一个shell脚本,名为pyenv-version-file,主要用于检测.python-version文件。如果检测出.python-version文件,则会输出其内容。否则会输出${PYENV_ROOT}/version文件的内容。
2. 源码分析
拆解成三部分进行分析:
(一)
#!/usr/bin/env bash
# Usage: pyenv version-file [<dir>]
# Summary: Detect the file that sets the current pyenv version
set -e
[ -n "$PYENV_DEBUG" ] && set -x
target_dir="$1"
set命令选项及其含义:
各个选项可组合使用,如:set -e -x
选项 | 含义 |
---|---|
-e | 若函数返回值不等于0,则立即退出shell。 注意set -e只在单独调用函数的地方有用,若加入如取反 ‘!’ ,‘||’ 等运算符,在函数返回非0时并不会退出shell。 |
-x | 显示执行过程的指令及参数值,一般debug的时候使用。 |
$符号的各种含义:
符号 | 含义 |
---|---|
$0 | 执行脚本的文件名,Shell 的命令本身 |
$1 - $9 | 表示 Shell 的第1到第9个参数 |
$? | 显示最近命令的执行结果,函数返回值 |
$# | 传递到脚本的参数个数 |
$$ | 脚本运行的当前进程 ID 号 |
$* | 以一个单字符串显示所有向脚本传递的参数 |
$! | 后台运行的最后一个进程的 ID 号 |
$- | 显示 Shell 使用的当前选项 |
(二)
find_local_version_file() {
local root="$1"
while ! [[ "$root" =~ ^//[^/]*$ ]]; do
if [ -f "${root}/.python-version" ]; then
echo "${root}/.python-version"
return 0
fi
[ -n "$root" ] || break
root="${root%/*}"
done
return 1
}
while 条件; do 语句 done
当条件为真时,执行语句,直到条件为假时退出。
=~
用于正则匹配,如果左侧表达式等于右侧的形式,则返回真,否则为假。
^//
表示以//开头;[^/]*
表示匹配/以外的任意字符,0次及以上次数;$
和前面的字符搭配,代表以前面匹配结果为结尾。
叹号(!)
对后面的条件式结果取反。然后再结合上下文,这里如果root变量如果是以 // 开头,并且后面没有 / ,结果为假。例如:// 或者 //abc等等
root%/*
将root变量值中的最后一个 / 及任意字符去除掉。
注:正则表达式比较复杂的时候,可以在notepad++上试验,比较直观。
(三)
if [ -n "$target_dir" ]; then
find_local_version_file "$target_dir"
else
find_local_version_file "$PYENV_DIR" || {
[ "$PYENV_DIR" != "$PWD" ] && find_local_version_file "$PWD"
} || echo "${PYENV_ROOT}/version"
fi
|
在Linux中,此符号是作为管道符来使用的,将 ‘|’前面命令的输入当做后面命令的输入。
&
用 ‘&’ 连接的多个符号将同时执行,不管命令是否执行成功。
||
逻辑或,当 ‘||’ 前面的语句结果为假时,后面的语句才会执行,若为真时,后面语句不会执行。
&&
逻辑与,当 ‘&&’ 前面语句结果为假时,后面语句不会执行,整条语句返回假。