введите базовое имя пути в команду find exec - PullRequest
0 голосов
/ 10 мая 2018

У меня есть команда PHP, которая работает:

php ~/.composer/vendor/bin/upgrade-code add-namespace "Vendor\Module\Finaldir" mymodule/finaldir  --write -r -vvv" \;

Я хотел бы заключить это в вызов find -exec (или аналогичный), чтобы сделать это рекурсивно для папок.

find mymodule/src -mindepth 1 -maxdepth 2 -type d -exec sh -c "DIR=$(basename {}); php ~/.composer/vendor/bin/upgrade-code add-namespace "Vendor\\Module\\${DIR}" {}  --write -r -vvv" \;

К сожалению, приведенный выше код не работает (а также не включает заглавную букву для переменной basename (DIR)).

Каков наилучший способ достичь этого?

Я не женат, чтобы найти вообще, я счастлив использовать что-нибудь еще, но, надеюсь, я могу держать это в одной строке.

СПАСИБО ТАКОЕ!

1 Ответ

0 голосов
/ 10 мая 2018

В основном это проблема цитирования оболочки и очень мало общего с find как таковым.

В оболочке Unix (например, bash) расширения переменных, такие как ${dir}, выполняются оболочкой перед передачей в утилиту командной строки, если они не заключены в одинарные кавычки . Вы можете увидеть результат этого с помощью команды echo:

$ dir=/home/rici
$ echo $dir     # Unquoted; the expansion is performed
/home/rici
$ echo "$dir"   # Double-quoted; the expansion is performed
/home/rici
$ echo '$dir'   # Single-quoted; the string is passed unmodified
$dir

(Примечание. Не следует использовать имена переменных оболочки all-caps. Имена переменных в all-caps, такие как $PATH и $USER, зарезервированы для использования самой системой. Ваши собственные имена переменных должны находиться в строчные.)

Разница между простой версией и версией в двойных кавычках заключается в том, что версия в двойных кавычках сохраняет пробелы и символы шаблонов файлов, в то время как версия без кавычек эффективно разбивает результат раскрытия на отдельные слова, а затем пытается развернуть файл закономерности в результате:

$ ls             # Files in this directory
a  b
$ dir='go   *'   # Note extra spaces
$ echo $dir      # The variable's value is re-split and expanded
go a b
$ echo "$dir"    # Just the value of the variable
go   *
$ echo '$dir'    # Just the characters of the argument
$dir

Обратите внимание, что в версии без кавычек три пробела, следующие за go, исчезли. Значение $dir было разделено на два слова, а затем, поскольку второе слово является шаблоном файла, оно расширяется на два имени файла. Таким образом, echo вызывается с тремя аргументами - go, a и b - которые он печатает с одним пробелом, разделяющим их.

Когда утилита командной строки является интерпретатором оболочки, это влияет на то, принадлежит ли используемая переменная внешней оболочке (и раскрывается ли она до того, как командная строка передается во внутреннюю оболочку), или передается в виде буквенной строки во внутреннюю. оболочка, которая затем расширяет его при выполнении:

$ dir=outer
$ bash -c "dir=inner; echo $dir"
outer

$ bash -c 'dir=inner; echo $dir'
inner

Ни одна из этих формулировок не является действительно правильной, поскольку внутренняя оболочка видит расширение параметра без кавычек, которое может привести к нежелательному разделению слов и расширению имени файла. Обычно версия, которую мы бы использовали, была бы:

bash -c 'dir=inner; echo "$dir"'

(В этом случае, поскольку двойные кавычки находятся в одинарных кавычках, они также обрабатываются внешней оболочкой как обычные символы, поэтому они передаются во внутреннюю оболочку.)

Одна из проблем с find -exec bash -c заключается в том, что имя файла, вставленное в командную строку с помощью find -exec, вставляется как есть. Это позволяет использовать тщательно продуманное имя файла для атаки .

Чтобы избежать этого, мы обычно пользуемся тем фактом, что bash -c также позволяет нам передавать позиционные аргументы в оболочку. Аргументы bash -c после интерпретируемой команды присваиваются $0, $1 и т. Д. Так как $0 не является реальным позиционным аргументом - это должно быть имя скрипта - мы обычно ставим фиктивный аргумент (_ в примере ниже) после аргумента команды и перед реальными позиционными аргументами. Итак, мы получим что-то вроде этого:

find ... -exec bash -c 'echo "$1"' _ {} \;

Здесь я тщательно заключил аргумент командной строки в одинарные кавычки, чтобы он передавался как есть; внутри аргумента командной строки я дважды заключаю в кавычки расширение параметра, чтобы пробелы и звезды не вызывали никаких проблем, а затем я получаю find -exec для передачи имени файла в качестве третьего аргумента bash -c, где оно становится $1. Я надеюсь, что все ясно.

Итак, чтобы вернуться к исходному вопросу, мы можем применить вышеописанный шаблон. Но я собираюсь сделать одно небольшое изменение; вместо использования basename, чтобы найти последний компонент имени файла, я собираюсь использовать слегка загадочный синтаксис оболочки для удаления префикса переменной. ${var##*/} принимает значение $var и затем удаляет самый длинный префикс, соответствующий шаблону */. (Один # был бы самым коротким соответствием.) Самый длинный префикс соответствия */ - это полный путь к каталогу, поскольку он простирается до последнего /; то, что осталось после удаления, является именно базовым именем.

find mymodule/src -mindepth 1 -maxdepth 2 -type d \
     -exec sh -c 'dir=${1##*/}; php ~/.composer/vendor/bin/upgrade-code add-namespace "Vendor\\Module\\$dir" "$dir" --write -r -vvv' _ {} \;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...