我使用此命令对目录中的所有图像进行蒙太奇:
gmic *jpg -gimp_montage 4,\""V(H(0,1),H(2,V(3,4)))"\",1,1.0,0,5,0,0,0,255,0,0,0,0 -o -0000."$(date)".jpg
我想在目录及其子目录中递归运行此命令。因此,在每个目录中,我将创建该目录中图像的蒙太奇。
我试过:
find -exec gmic *jpg -gimp_montage 4,\""V(H(0,1),H(2,V(3,4)))"\",1,1.0,0,5,0,0,0,255,0,0,0,0 -o -0000."$(date)".jpg
但这给了我错误
find: missing argument to `-exec'
我也尝试过
find -exec gmic -gimp_montage 4,\""V(H(0,1),H(2,V(3,4)))"\",1,1.0,0,5,0,0,0,255,0,0,0,0 -o -0000."$(date)".jpg {} \;
这给了我以下错误:
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Output image [] as file '-0000.Fri Mar 13 04:33:44 EDT 2015.jpg', with quality 100%.
[gmic]-0./ *** Error *** Command '-output': File '-0000.Fri Mar 13 04:33:44 EDT 2015.jpg', instance list (0,(nil)) is empty.
[gmic] *** Error in ./ *** Command '-output': File '-0000.Fri Mar 13 04:33:44 EDT 2015.jpg', instance list (0,(nil)) is empty.
答案1
好的,所以您想要在目录树中的每个目录中运行命令 - 当前目录、其子目录、它们的子目录等。要做的第一件事是枚举有问题的目录。使用该find
命令,告诉它仅列出目录:
find . -type d
您要在每个目录中运行的命令是
gmic ./*jpg -gimp_montage 4,\""V(H(0,1),H(2,V(3,4)))"\",1,1.0,0,5,0,0,0,255,0,0,0,0 -o -0000."$(date)".jpg
这是一个 shell 命令,包含通配符扩展和命令替换。您需要运行一个 shell 来执行它。由于该 shell 将被告知要做什么find
,因此它不会是您正在运行find
的 shell:您需要告诉find
它运行一个 shell。将您想要充当 shell 参数的目录传递给 shell。
find . -type d -exec sh -c '…' {} \;
在调用 之前gmic
,您需要在该脚本中执行几件事:更改到相关目录,并检查它是否包含.jpg
文件。
find . -type d -exec sh -c '
cd "$0" || exit
set -- *.jpg
if [ -e "$1" ]; then
gmic "$@" -gimp_montage 4,\""V(H(0,1),H(2,V(3,4)))"\",1,1.0,0,5,0,0,0,255,0,0,0,0 -o -0000."$(date)".jpg
fi
' {} \;
或者,您可以告诉find
列出.jpg
文件。然而,这使得每个目录仅执行一个命令变得困难。
如果您的 shell 是 bash,而不是 plain sh
,则可以使用其**
通配符递归到目录。这比使用更容易find
。在 bash ≤4.2 中,还要注意**
遍历目录的符号链接。您还可以稍微简化文件存在测试。
shopt -s globstar nullglob
for dir in ./**/*/; do
files=("$dir/"*.jpg)
if [[ ${#files[@]} -ne 0 ]]; then
gmic "${files[@]}" -gimp_montage 4,\""V(H(0,1),H(2,V(3,4)))"\",1,1.0,0,5,0,0,0,255,0,0,0,0 -o "$dir/-0000.$(date)".jpg
fi
done
在 zsh 中,您可以使用历史修改器在一个全局限定符枚举包含.jpg
文件的目录,然后过滤结果数组以保留每个目录的单个副本。
dirs=(./**/*.jpg(:h))
for dir in ${(u)dirs}; do
gmic $dir/*.jpg -gimp_montage 4,\""V(H(0,1),H(2,V(3,4)))"\",1,1.0,0,5,0,0,0,255,0,0,0,0 -o "$dir/-0000.$(date).jpg"
done
(旁白:-0000.Sat Mar 14 15:51:28 CET 2015.jpg
对于文件来说,这是一个非常奇怪的名称。名称以 开头的文件-
往往会引起问题,因为它们看起来像命令的选项。以按字典顺序排序与按时间顺序排序相同的格式操作日期更方便,例如20150314-145128
. )
答案2
与其余评论一样,我不确定您需要什么来允许您运行任何命令,而不是 -exec 或将位管道传输到 while 或 for 循环中。 exec 选项将允许您使用“{}”来代替它找到的任何内容(完整路径,而不是相对路径)。这是 -exec 选项和 for 循环的快速示例。
$ tree
.
|-- a
| |-- a
| | `-- a
| `-- b
`-- b
|-- a
`-- b
7 directories, 0 files
$ find . -type d -exec touch {}/foo \
$ tree
.
|-- a
| |-- a
| | |-- a
| | | `-- foo
| | `-- foo
| |-- b
| | `-- foo
| `-- foo
|-- b
| |-- a
| | `-- foo
| |-- b
| | `-- foo
| `-- foo
`-- foo
7 directories, 8 files
$ for i in $(find . -type f); do mv $i $i.moved; done
$ tree
.
|-- a
| |-- a
| | |-- a
| | | `-- foo.moved
| | `-- foo.moved
| |-- b
| | `-- foo.moved
| `-- foo.moved
|-- b
| |-- a
| | `-- foo.moved
| |-- b
| | `-- foo.moved
| `-- foo.moved
`-- foo.moved
7 directories, 8 files