Ответ 1
Проблема с вашей первоначальной попыткой:
find www/*.html -type f -exec sh -c "echo $(basename {})" \;
заключается в том, что код $(basename {})
выполняется один раз, перед выполнением команды find
. Результатом одиночного basename
является {}
, так как это basename {}
как имя файла. Таким образом, команда, выполняемая find:
sh -c "echo {}"
для каждого найденного файла, но find
фактически заменяет исходное (немодифицированное) имя файла каждый раз, потому что символы {}
отображаются в строке, которая должна быть выполнена.
Если вы хотите, чтобы он работал, вы можете использовать одинарные кавычки вместо двойных кавычек:
find www/*.html -type f -exec sh -c 'echo $(basename {})' \;
Однако, если echo
повторить стандартный вывод, который basename
написал бы на стандартный вывод в любом случае, это немного бессмысленно:
find www/*.html -type f -exec sh -c 'basename {}' \;
и мы можем, тем не менее, уменьшить это:
find www/*.html -type f -exec basename {} \;
Не могли бы вы также объяснить разницу между одинарными кавычками и двойными кавычками здесь?
Это обычное поведение оболочки. Возьмем немного другую команду (но только немного - имена файлов могут быть в любом месте в каталоге www
, а не только на одном уровне вниз), и посмотрите на одну кавычку (SQ) и двойную кавычку (DQ) версии команды:
find www -name '*.html' -type f -exec sh -c "echo $(basename {})" \; # DQ
find www -name '*.html' -type f -exec sh -c 'echo $(basename {})' \; # SQ
Одиночные кавычки передают материал, заключенный непосредственно в команду. Таким образом, в командной строке SQ оболочка, запускающая find
, удаляет закрывающие кавычки, а команда find
видит свой аргумент $9
как:
echo $(basename {})
потому что оболочка удаляет кавычки. Для сравнения, материал в двойных кавычках обрабатывается оболочкой. Таким образом, в командной строке DQ оболочка (которая запускает find
, а не ту, которая запускается find
), видит $(basename {})
часть строки и выполняет ее, возвращаясь {}
, поэтому строка, которую она передает до find
в качестве аргумента $9
:
echo {}
Теперь, когда find
выполняет свое действие -exec
, в обоих случаях он заменяет {}
на имя файла, которое он только что нашел (для аргумента, www/pics/index.html
). Таким образом, вы выполняете две разные команды:
sh -c 'echo $(basename www/pics/index.html)' # SQ
sh -c "echo www/pics/index.html" # DQ
Там есть (небольшой) нотационный чит - это эквивалентные команды, которые вы вводите в оболочку. $2
запускаемой оболочки фактически не содержит кавычек в любом случае - запущенная оболочка не видит никаких кавычек.
Как вы можете видеть, команда DQ просто переименовывает имя файла; команда SQ запускает команду basename
и фиксирует ее выход, а затем перехватывает захваченный вывод. Немного редукционистского мышления показывает, что команда DQ может быть записана как -print
вместо использования -exec
, а команда SQ может быть записана как -exec basename {} \;
.
Если вы используете GNU find
, он поддерживает действие -printf
, за которым могут следовать Директивы формата, так что запуск basename
не требуется. Однако это доступно только в GNU find
; остальная часть обсуждения здесь применима к любой версии find
, с которой вы, вероятно, столкнетесь.