在每个子目录中运行带有通配符的命令

在每个子目录中运行带有通配符的命令

我使用此命令对目录中的所有图像进行蒙太奇:

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

相关内容