作者:E4b9a6, 创建:2021-03-09, 字数:5755, 已阅:298, 最后更新:2021-03-09
经常需要使用bash批量处理文件格式,每次都要查询一些基础语法很麻烦
所以以遍历文件夹目录处理图片为例总结一些使用Bash遍历处理文件夹时常见的语法
Bash遍历的方法比较简单,与大部分编程语言的for循环没有明显区别
#/bin/sh
#author: chancel.yang
for file in ./*
do
if test -f "$file"
then
echo -e "$file"
fi
done
脚本输出如下
➜ bash demo.sh
./a.png
./b.png
./c.jpg
./demo.sh
这种遍历在大部分情况下都很实用
上面的输出中会发现执行的脚本demo.sh也在其中,而且只能针对当前路径进行处理
那么试试添加自定义路径,然后将demo脚本放到其他位置
#/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
输出如下
➜ 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
执行如下
➜ 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]
获取传递进来的参数外,还有一些常见的特殊参数值可以直接使用
参数 | 说明 |
---|---|
$# | 参数总个数 |
$$ | 当前PID号 |
上面添加自定义路径之后,输出 $file
也携带了路径信息,实际使用时多要用到文件名,扩展名等
下面演示如何提取文件路径、文件名(带扩展名)、文件名、扩展名
#/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
执行后输出如下
➜ 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##*.}
Bash提供test关键字进行条件判断,偶尔也会看到if [ string1 != string2 ]
上面俩个写法是等价的,即test
与[
两者是等价的,都是Bash中的关键字,区别是[
要求最后一个参数必须是]
由于
[
是一个关键字,而]
是一个参数,所以必须有空格,[string1 != string2]这种没有空格的写法是错误的
由于两者是等价的,所以以下针对test进行说明,将脚本中的test condition
等价替换成[ condition ]
也是成立的
以下是常见的条件判断示例脚本
#/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
执行输出如下
➜ 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
执行输出如下
➜ bash demo.sh
string_1 is null
string_2 is not null
使用test进行判断时,推荐使用双引号括起来变量,否则因为变量内容带空格而达不到预期的执行效果
考虑到变量如路径可能是用户输入的,除了双引号来避免变量路径中带有空格外,还可以使用[[]]
来避免内容拆分
[
与test
判断时都会对内容进行拆分,如test="go to"
会被识别成go
与to
两个参数
与[
不同,[[
与]]
均是命令,]]
并不是参数
以下代码演示两者的不同
#/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
输出如下
➜ bash demo.sh
demo.sh: line 7: test: too many arguments
go to == 'go to'
go to == 'go to'
到这里,写一个遍历脚本的基本语法已经齐全,下面是一个转换指定目录中所有文件为webp图片的遍历脚本,以供参考
#/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"
参考资料