각 하위 디렉터리에서 와일드카드를 사용하여 명령 실행

각 하위 디렉터리에서 와일드카드를 사용하여 명령 실행

이 명령을 사용하여 디렉토리의 모든 이미지를 몽타주합니다.

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

이는 와일드카드 확장 및 명령 대체를 포함하는 쉘 명령입니다. 이를 실행하려면 쉘을 실행해야 합니다. 쉘이 무엇을 해야할지 지시받을 것이기 때문에 , 당신이 실행하고 있는 쉘 find은 아닐 것입니다 . 쉘을 실행하라고 지시해야 합니다. 쉘 인수로 제공하려는 디렉토리를 쉘에 전달하십시오.findfind

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그러나 이로 인해 디렉터리당 하나의 명령만 실행하기가 어렵습니다.

쉘이 plain이 아닌 bash인 경우 와일드카드를 사용하여 디렉토리로 재귀할 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

관련 정보