我正在使用 Manjaro GNU/Linux。我有一个名为files
;的目录在这个目录下,我有大约 650 个子目录,名称如file1
、file2
、file3
等。
每个子目录下有 2 到 11 个.tif
图像。
我想编写一个命令或脚本来自动将所有.tif
图像转换为.jpeg
或.jpg
使它们保留在相同的子目录中并具有与以前相同的名称。
我知道有这样的命令:
convert source.tif ~/converted.jpg
你能帮忙吗?
谢谢!
答案1
最简单的方法是find
执行一个简短的内联脚本,该脚本使用.tif
文件名后缀转换每个找到的文件:
find files/ -name '*.tif' -type f -exec sh -c '
for pathname do
convert "$pathname" "${pathname%.tif}.jpg"
done' sh {} +
上面的内联脚本将通过批量找到的常规文件的路径名(其后缀在目录下找到)sh -c
来调用。参数替换会从 的值中删除后缀并附加到末尾。find
.tif
files
${pathname%.tif}.jpg
.tif
$pathname
.jpg
用作files/file*/
搜索路径,而不是仅在以 string 开头files/
的这约 650 个子目录中查找,而忽略任何其他子目录。files
file
这会将文件保留在原位,但如果您在循环中的命令后面.tif
添加,则可以在成功转换后删除它们。&& rm "$pathname"
convert
在zsh
shell 中,您可以放弃find
并依赖 shell 更高级的文件名匹配和字符串操作功能:
for pathname in files/**/*.tif(D-.); do
convert $pathname $pathname:r.jpg
done
此处,将展开为名称以目录中或目录下任意位置files/**/*.tif(D-.)
结尾的所有常规文件的列表。通配符末尾的 使得通配符模式仅匹配常规文件(可能具有“隐藏”名称)。.tif
files
(D-.)
之后给出路径名的“根”(不带文件扩展名:r
的$pathname
名称)。
用于files/file*/**/*.tif(D-.)
将搜索限制为仅file*
搜索子目录中的文件。
使用bash
shell,您可以执行与上面类似的操作,如下所示:
shopt -s dotglob failglob globstar
for pathname in files/**/*.tif; do
convert "$pathname" "${pathname%.tif}.jpg"
done
此处设置的 shell 选项启用隐藏名称的通配和通配运算符的使用**
。它还会使不匹配的模式生成错误,就像zsh
shell 中的默认情况一样。
答案2
对于 7,000 多个文件,您将需要花很长时间按顺序执行它们,因此我建议利用当今的多核 CPU 并使用GNU 并行让它们并行转换。它不仅速度更快,还可以非常简单地为您操作后缀,并为您提供进度报告并进行空运行,看看它会做什么,而无需实际执行任何操作。
看起来bash
像这样:
shopt -s failglob globstar
parallel --dry-run magick {} {.}.jpg ::: files/**/*.tif
输出
magick files/file1/1.tif files/file1/1.jpg
magick files/file2/1.tif files/file2/1.jpg
magick files/file1/2.tif files/file1/2.jpg
magick files/file2/2.tif files/file2/2.jpg
magick files/file3/1.tif files/file3/1.jpg
magick files/file3/2.tif files/file3/2.jpg
如果看起来正确,请删除--dry-run
并再次进行真正的操作。
如果您有太多文件并出现错误,您可以将文件名通过管道传输到magick
from find
,这里我还添加了--bar
进度条:
find files -iname "*.tif" -print0 | parallel -0 --dry-run --bar magick {} {.}.jpg
请注意,与某些答案不同,如果您的 TIFF 文件具有大写后缀,这也将起作用。
答案3
cd
进入包含子文件夹的主目录后。
IFS=$'\n'
for i in $(find -type f -name "*tiff"); do
echo $i
convert $i $i.jpg
done
find -type f -name "*tiff" -exec rm {} \;
IFS
是内部字段分隔符
我看到的一个问题是我无法提取basename
文件的内容
在移动到大文件夹之前,不要忘记先在小文件夹中尝试
答案4
我会使用类似于此的脚本:
#!/bin/bash
if [[ $# -gt 0 ]]
then
if [[ -d $1 ]]
then
cd $1
else
echo "Given path leads to a file or the directory you are loking does not exist!"
exit 1
fi
fi
for dir in */
do
echo "Changing directory to $dir"
cd $dir
for image in *
do
if [[ -f "$image" ]]
then
filename="${image%.*}"
extension="${image##*.}"
if [[ "$extension" =~ ^ti[f]{1,2}$ ]]; then
echo "Converting $image to ${filename}.jpg"
convert "$image" -compress JPEG -quality 50 "${filename}.jpg"
fi
fi
done
cd - > /dev/null
done
设置你的脚本:
- 将其另存为batchJPEGConvert.sh
- 使用
chmod 755 batchJPEGConvert.sh
命令使该文件可执行 - 使用
sudo cp batchJPEGConvert.sh /usr/local/bin
命令使该脚本可以在您的系统中访问
batchJPEGConvert.sh
您可以通过键入或 来运行此脚本batchJPEGConvert.sh path
。第一个选项将在当前工作目录中运行此脚本。另一个选项将尝试将工作目录更改为给定的小路并在那里运行脚本。该脚本将仅有的转换以 .tiff 或 .tif 扩展名结尾的文件。它还将应用 JPEG 压缩。
请注意,此脚本仅适用于结构类似于此的目录:
test
├── 1
│ ├── polski.jpg
│ └── polski.tiff
└── 2
├── polski.jpg
└── polski.tif