提取文件名以命名其他文件时出错
Error when extracting a filename to name other files
我正在尝试使用 FFmpeg 将视频转换为 Bash 中的图像。我想使用视频的文件名来命名相应的图像(后跟一个整数)。
如果我在同一目录中导出文件,我能够做到这一点:
for file in `find . -name "*.mp4"`; do ffmpeg -i $file -q 1 $file'_'%d.jpeg; done
但是,如果我要将图像导出到所需的目录,则会出现错误。看来 $file 的值不仅仅是文件名,而是一个目录。
我在尝试什么:
for file in `find . -name "*.mp4"`; do ffmpeg -i $file -q 1 ~/testfolder/$file'_'%d.jpeg; done
我的问题是:我怎样才能正确提取要在此处使用的文件名?
bash命令basename
可用于此。
在这种情况下,下面应该只列出文件:
for file in $(find . -name "*.mp4"); do echo $(basename $file); done
您可以在原始代码中使用 $(basename $file)
来仅获取文件名。
for file in $(find . -name "*.mp4"); do
ffmpeg -i "${file}" -q 1 "~/testfolder/$(basename $file)'_'%d.jpeg"
done
这样做,因为它可以处理包含任何特殊字符(包括换行符,很少使用但在文件名中有效)的文件。
destdir=~/testfolder/
while read -u 5 -r -d '' file
do
name=$(basename "$file")
ffmpeg -i "$file" -q 1 "$destdir/${file}_%d.jpeg" </dev/null
done 5< <(find . -name "*.mp4" -print0)
basename
命令是一个外部程序。您可以使用以下行仅使用 shell 扩展来获得相同的结果:
name=${file%/}
name=${name##*/}
你既不需要基名也不需要循环;
您可以使用 -type f
来避免 find
在其结果中报告目录,并结合 -exec
选项直接执行您的命令。
像这样的东西应该适用于你所有的 mp4 文件:
find . -type f -name '*.mp4' -exec bash -c 'ffmpeg -i [=10=] -q 1 [=10=]'_'%d.jpeg' {} \;
查看小演示测试:
$ find . -type f -name 'a*.txt' -exec bash -c 'echo ffmpeg -i [=11=] ' {} \;
ffmpeg -i ./a.txt
ffmpeg -i ./a spaced file.txt
ffmpeg -i ./aa.txt
ffmpeg -i ./cheatsheets/awk-cheat-sheet-gv.txt
如您所见,第二个文件的文件名中有空格,但被 find
正确处理。
相反,这样的间隔文件将以 for loop
中断。
如果您坚持用循环来完成这项工作,那么这必须是 Fred 所建议的 while 循环。
作为对 Fred 解决方案的修改,您可以使用 find
的 -printf
功能避免使用 basename:
while read -r -d '' file;do
ffmpeg -i "$file" -q 1 "${file}_%d.jpeg"
done < <(find . -name "*.mp4" -printf %f\0)
-printf %f
根据 find
的手册页打印剥离的文件名,并在每个文件名后附加 \0
(空字符)我们确保正确的文件名处理,即使名称包含空格或其他特殊字符。
小测试:
$ while read -r -d '' file;do echo "ffmpeg -i $file -q 1 ${file}_%d.jpeg";done < <(find . -name "a*.txt" -printf %f\0)
ffmpeg -i a.txt -q 1 a.txt_%d.jpeg
ffmpeg -i a spaced file.txt -q 1 a spaced file.txt_%d.jpeg
ffmpeg -i aa.txt -q 1 aa.txt_%d.jpeg
ffmpeg -i awk-cheat-sheet-gv.txt -q 1 awk-cheat-sheet-gv.txt_%d.jpeg
我正在尝试使用 FFmpeg 将视频转换为 Bash 中的图像。我想使用视频的文件名来命名相应的图像(后跟一个整数)。
如果我在同一目录中导出文件,我能够做到这一点:
for file in `find . -name "*.mp4"`; do ffmpeg -i $file -q 1 $file'_'%d.jpeg; done
但是,如果我要将图像导出到所需的目录,则会出现错误。看来 $file 的值不仅仅是文件名,而是一个目录。
我在尝试什么:
for file in `find . -name "*.mp4"`; do ffmpeg -i $file -q 1 ~/testfolder/$file'_'%d.jpeg; done
我的问题是:我怎样才能正确提取要在此处使用的文件名?
bash命令basename
可用于此。
在这种情况下,下面应该只列出文件:
for file in $(find . -name "*.mp4"); do echo $(basename $file); done
您可以在原始代码中使用 $(basename $file)
来仅获取文件名。
for file in $(find . -name "*.mp4"); do
ffmpeg -i "${file}" -q 1 "~/testfolder/$(basename $file)'_'%d.jpeg"
done
这样做,因为它可以处理包含任何特殊字符(包括换行符,很少使用但在文件名中有效)的文件。
destdir=~/testfolder/
while read -u 5 -r -d '' file
do
name=$(basename "$file")
ffmpeg -i "$file" -q 1 "$destdir/${file}_%d.jpeg" </dev/null
done 5< <(find . -name "*.mp4" -print0)
basename
命令是一个外部程序。您可以使用以下行仅使用 shell 扩展来获得相同的结果:
name=${file%/}
name=${name##*/}
你既不需要基名也不需要循环;
您可以使用 -type f
来避免 find
在其结果中报告目录,并结合 -exec
选项直接执行您的命令。
像这样的东西应该适用于你所有的 mp4 文件:
find . -type f -name '*.mp4' -exec bash -c 'ffmpeg -i [=10=] -q 1 [=10=]'_'%d.jpeg' {} \;
查看小演示测试:
$ find . -type f -name 'a*.txt' -exec bash -c 'echo ffmpeg -i [=11=] ' {} \;
ffmpeg -i ./a.txt
ffmpeg -i ./a spaced file.txt
ffmpeg -i ./aa.txt
ffmpeg -i ./cheatsheets/awk-cheat-sheet-gv.txt
如您所见,第二个文件的文件名中有空格,但被 find
正确处理。
相反,这样的间隔文件将以 for loop
中断。
如果您坚持用循环来完成这项工作,那么这必须是 Fred 所建议的 while 循环。
作为对 Fred 解决方案的修改,您可以使用 find
的 -printf
功能避免使用 basename:
while read -r -d '' file;do
ffmpeg -i "$file" -q 1 "${file}_%d.jpeg"
done < <(find . -name "*.mp4" -printf %f\0)
-printf %f
根据 find
的手册页打印剥离的文件名,并在每个文件名后附加 \0
(空字符)我们确保正确的文件名处理,即使名称包含空格或其他特殊字符。
小测试:
$ while read -r -d '' file;do echo "ffmpeg -i $file -q 1 ${file}_%d.jpeg";done < <(find . -name "a*.txt" -printf %f\0)
ffmpeg -i a.txt -q 1 a.txt_%d.jpeg
ffmpeg -i a spaced file.txt -q 1 a spaced file.txt_%d.jpeg
ffmpeg -i aa.txt -q 1 aa.txt_%d.jpeg
ffmpeg -i awk-cheat-sheet-gv.txt -q 1 awk-cheat-sheet-gv.txt_%d.jpeg