有一种常见的模式,即您拥有一对文件,其中一对文件的一个名称可以很容易地从另一个文件中派生出来。如果您知道的文件名称为 X,而另一个文件名称为 Y,则您有以下常见用例。
- 对于重命名,Y 是 X,移除了扩展名和/或添加了日期戳。
- 对于转码,Y 是 X,具有不同的扩展名,可能还有不同的目录。
- 对于许多数据分析任务,X 和 Y 共享文件名的某些部分,但具有不同的参数或扩展名。
所有这些都适用于相同的粗略代码框架。
for x in path/to/base*.ext; do
dir=${x%/*} # Trim trailing file name, keep dir
base=${x##*/} # Trim any leading directory
# In this case, $y has a different subdirectory and a different extension
y=${dir%/to}/from/${base%.ext}.newext
# Maybe check if y exists? Or doesn't exist?
if [ -e "$y" ]; then
echo "$0: $y already exists -- skipping" >&2
continue
fi
mv or ffmpeg or awk or whatever "$x" and "$y"
done
这里的关键是观察到y 可以通过一些简单的变量替换从x 派生而来。因此,您循环遍历 x 值,并找出循环内对应的 y 值。
在这里,我们使用了 shell 的内置 ${variable#prefix} 和 ${variable%suffix} 运算符来返回变量的值,其中任何前导 prefix 或尾随 suffix 分别被修剪掉。 (还有 ## 和 %% 来匹配最长的,而不是最短的,可能的匹配。# 或 % 之后的表达式是一个常规的 shell glob 模式。)这些通常应该是你所需要的,尽管您经常看到 sed 或 awk 脚本,即使是对于这项琐碎的工作(实际上您通常应该尽量避免外部过程),当然还有更苛刻的转换。
如果您需要循环遍历分散在不同目录中的 x 文件,那么循环应该以类似的方式开始
find dir1 dir2 etc/and/so/forth -type f -name 'x-files*.ext' -print |
while IFS='' read -r x; do
:
类似问题中常见的问题是未能正确引用$x 和$y 的答案。通常,任何包含文件名的变量都应该用双引号括起来。
在 X 和 Y 不相关的情况下,一种常见的解决方案是遍历包含映射的 here 文档:
while read -r x y; do
: stuff with "$x" and "$y"
done <<'____HERE'
first_x_value first_y_value
another_x corresponding_y
random surprise
____HERE