Linux下使用Bash遍历文件夹语法解析
经常需要使用bash批量处理文件格式,每次都要查询一些基础语法很麻烦
所以以遍历文件夹目录处理图片为例总结一些使用Bash遍历处理文件夹时常见的语法
2. 遍历
Bash遍历的方法比较简单,与大部分编程语言的for循环没有明显区别
Bashcontent_copy#/bin/sh #author: chancel.yang for file in ./* do if test -f "$file" then echo -e "$file" fi done
脚本输出如下
Bashcontent_copy➜ bash demo.sh ./a.png ./b.png ./c.jpg ./demo.sh
这种遍历在大部分情况下都很实用
3. 路径处理
上面的输出中会发现执行的脚本demo.sh也在其中,而且只能针对当前路径进行处理
那么试试添加自定义路径,然后将demo脚本放到其他位置
Bashcontent_copy#/bin/sh #author: chancel.yang path="/mnt/SDA/TMP/test" for file in $path/* do if test -f "$file" then echo -e "$file" fi done
输出如下
Bashcontent_copy➜ bash /mnt/SDA/TMP/demo.sh /mnt/SDA/TMP/test/a.png /mnt/SDA/TMP/test/b.png /mnt/SDA/TMP/test/c.jpg
在实际处理中,可以将$path
调整为入参,脚本如下
#/bin/sh #author: chancel.yang for file in $1/* do if test -f "$file" then echo -e "$file" fi done
执行如下
Bashcontent_copy➜ bash demo.sh "/mnt/SDA/TMP/test"
/mnt/SDA/TMP/test/a.png
/mnt/SDA/TMP/test/b.png
/mnt/SDA/TMP/test/c.jpg
$0是文件名是名称,如demo.sh
除了$[number]
获取传递进来的参数外,还有一些常见的特殊参数值可以直接使用
4. 提取文件名
上面添加自定义路径之后,输出 $file
也携带了路径信息,实际使用时多要用到文件名,扩展名等
下面演示如何提取文件路径、文件名(带扩展名)、文件名、扩展名
Bashcontent_copy#/bin/sh #author: chancel.yang path="/mnt/SDA/TMP/test" for file in $path/* do if test -f "$file" then echo "dirname: $(dirname $file)" echo "filename: $(basename $file)" filename=$(basename $file) echo "filename(suffix): ${filename%%.*}" echo "suffix: ${filename#*.}" fi done
执行后输出如下
Bashcontent_copy➜ bash demo.sh dirname: /mnt/SDA/TMP/test filename: a.png filename(suffix): a suffix: png dirname: /mnt/SDA/TMP/test filename: b.png filename(suffix): b suffix: png dirname: /mnt/SDA/TMP/test filename: c.jpg filename(suffix): c suffix: jpg
如果后缀有多个,如a.tar.gz
,其他不常见的提取如下
filename='a.tar.gz' # a.tar ${file%.*} # gz ${file##*.}
5. 条件判断5.1. test与[]
Bash提供test关键字进行条件判断,偶尔也会看到if [ string1 != string2 ]
上面俩个写法是等价的,即test
与[
两者是等价的,都是Bash中的关键字,区别是[
要求最后一个参数必须是]
由于
[
是一个关键字,而]
是一个参数,所以必须有空格,[string1 != string2]这种没有空格的写法是错误的
由于两者是等价的,所以以下针对test进行说明,将脚本中的test condition
等价替换成[ condition ]
也是成立的
5.2. 判断运算符
以下是常见的条件判断示例脚本
Bashcontent_copy#/bin/sh #author: chancel.yang a=100 b=200 c=100 echo -e "a="$a", b="$b", c="$c if test "$a" -eq "$c" then echo -e "a = c" fi if test "$a" -ne "$b" then echo -e "a != b" fi if test "$b" -gt "$a" then echo -e "b > a" fi dirname=`pwd` filename=$dirname/demo.sh echo -e "dirname: "$dirname", filename: "$filename if test -d "$dirname" then echo -e $dirname" is a folder" fi if test -f "$filename" then echo -e $filename" is a file" fi
执行输出如下
Bashcontent_copy➜ bash demo.sh a=100, b=200, c=100 a = c a != b b > a dirname: /mnt/SDA/TMP, filename: /mnt/SDA/TMP/demo.sh /mnt/SDA/TMP is a folder /mnt/SDA/TMP/demo.sh is a folder
条件判断数值类型时,其常见运算符参数列表如下
参数 说明 -eq 相等 -ne 不相等 -gt > -ge >= -lt < -le <=判断条件文件时,其常见运算符参数列表如下
参数 说明 -e 文件存在 -r 文件存在且可读 -w 文件存在且可写 -x 文件存在且可执行 -s 文件存在且内容不为空 -d 是目录 -f 是文件文件与数值内容的判断相对简单,接下来看看比较复杂的字符串判定
在test
中,判断字符串为空时,-z
表示当字符串为空时返回True,-n
表示字符串不为空时返回True
#/bin/sh #author: chancel.yang string_1="" string_2="hello" if test -z "$string_1" then echo -e "string_1 is null" fi if test -n "$string_2" then echo -e "string_2 is not null" fi
执行输出如下
Bashcontent_copy➜ bash demo.sh string_1 is null string_2 is not null
使用test进行判断时,推荐使用双引号括起来变量,否则因为变量内容带空格而达不到预期的执行效果
考虑到变量如路径可能是用户输入的,除了双引号来避免变量路径中带有空格外,还可以使用[[]]
来避免内容拆分
5.3. 特殊的[[]]
[
与test
判断时都会对内容进行拆分,如test="go to"
会被识别成go
与to
两个参数
与[
不同,[[
与]]
均是命令,]]
并不是参数
以下代码演示两者的不同
Bashcontent_copy#/bin/sh #author: chancel.yang a="go to" # 此处会报错 if test $a == "go to" then echo -e "$a == 'go to'" fi # 此处添加双引号可以正确判断 if test "$a" == "go to" then echo -e "$a == 'go to'" fi # 此处无需双引号也可以正确判断 if [[ $a == "go to" ]] then echo -e "$a == 'go to'" fi
输出如下
Bashcontent_copy➜ bash demo.sh demo.sh: line 7: test: too many arguments go to == 'go to' go to == 'go to'
6. 图片转换例子
到这里,写一个遍历脚本的基本语法已经齐全,下面是一个转换指定目录中所有文件为webp图片的遍历脚本,以供参考
Bashcontent_copy#/bin/sh #author: chancel.yang #date: 2022-06-14 show_help() { echo "$0 [-h|-?|--help] [--who me] [--why hhh]" echo "-h|-?|--help 显示帮助" echo "--path 文件夹路径" } while [[ $# -gt 0 ]]; do case $1 in -h | -\? | --help) show_help exit 0 ;; --in) in="${2}" shift ;; --out) out="${2}" shift ;; *) echo -e "Error: $0 invalid option '$1'\nTry '$0 --help' for more information.\n" >&2 exit -1 ;; esac shift done if !(test "$in") then echo "Please run --help for usage" exit fi if !(test "$out") then echo "Please run --help for usage" exit fi if !(test -d "$in") then echo "Error: $in is not a folder" exit fi if test -f "$out" then echo "Error: $out is a file" exit fi if [ ! -d "$out" ]; then mkdir $out fi for file in $in/* do filename=$(basename $file) if test -f "$file" then /usr/bin/ffmpeg -i $file -c:v libwebp $out/${filename%%.*}.webp echo "$file convert to $out/$filename.webp" fi done echo -e "Convert success"
参考资料
Bash技巧:对比 test、[、[[ 判断字符串是否为空的用法文章来源:
Author:chancel
link:http://www.chancel.me/markdown/linux-bash-traverse-folder-syntax-parsing