find: текущее имя файла оценивается как пустое в вложенной команде

Я пытаюсь переименовать кучу изображений в каталог в соответствии с их размерами. С этой целью я наращиваю свою команду шаг за шагом, используя команду identify Imagemagik. В настоящее время я использую echo и планирую переключить его на mv только echo сигналы будут правильно.

 find * -type f -exec echo "$(identify -format '%w-%h' {})" \; 

Это выводит пустую строку. Однако, когда я просто запускаю его без эха напрямую,

 find * -type f -exec identify -format '%w-%h' {} \; 

Он выводит размеры, как ожидалось. Почему не выполняется внутренняя команда?

Использование:

 find . -type f -exec sh -c 'echo "$(identify -format %w-%h "$1")"' sh {} \; 

объяснение

Проблема заключается в том, как bash расширяет переменные

 find * -type f -exec echo "$(identify -format '%w-%h' {})" \; 

Первый bash расширяет то, что находится в стороне $(...) :

 find * -type f -exec echo 'identify: unable to open image `{}': No such file or directory...' \; 

В какой момент find будет использовать один и тот же оператор exec для всех команд с довольно бесполезным аргументом. То, что вы хотите сделать, это подавить расширение bash внутри find exec. Вы можете остановить расширение bash, помещая их в одинарные кавычки

 find * -type f -exec echo '$(identify -format %w-%h {})' \; 

Но здесь мы полностью теряем расширение, мы можем ввести его обратно, запустив выражение с помощью sh -c

 find * -type f -exec sh -c 'echo "$(identify -format %w-%h {})"' \; 

Наличие {} внутри скрипта оболочки также может привести к неожиданным ошибкам при работе с пробелами или кавычками или любым символом, специальным для оболочки в именах файлов. Чтобы обойти это, вы должны переместить {} в качестве аргумента для sh:

 find * -type f -exec sh -c 'echo "$(identify -format %w-%h "$1")"' sh {} \; 

См. Этот вопрос / ответ для более подробного объяснения этого.

Наконец, вы можете заменить * . чтобы find найденные файлы в текущем каталоге самостоятельно (и включить скрытые и не сбой для имен файлов, начиная с - ).

Кроме того, вы можете добавить флаг -x в sh чтобы заставить его распечатать то, что было выполнено, чтобы помочь с отладкой команды – это может быть очень шумно для большого количества файлов.

Это потому, что echo не знает, что {} внутри себя, чтобы расширять его, только exec понимать {} , в этом случае вы должны использовать в режиме sh -c .

 find . -type f -exec sh -c 'echo "$(identify -format '%w-%h' "$1")"' sh '{}' \;