Php 将路径的basename注入find exec命令
我有一个PHP命令可以工作:Php 将路径的basename注入find exec命令,php,bash,silverstripe-4,Php,Bash,Silverstripe 4,我有一个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=$(base
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)变量的大写字母)
实现这一目标的最佳方式是什么
我并不是为了寻找而结婚的,我很乐意使用其他任何东西,但希望我能把它保持在一行
非常感谢你 这主要是一个shell引用问题,与
find
本身关系不大
在Unix shell(如bash)中,变量扩展(如${dir}
)在传递给命令行实用程序之前由shell执行,除非它们用单引号括起来。您可以使用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
(注意:您不应使用所有caps外壳变量名称。所有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
--它用一个空格分隔它们
当命令行实用程序是shell解释器时,这会影响所使用的变量是属于外壳(并在命令行传递到内部外壳之前展开),还是作为文本字符串传递到内部外壳,然后在执行时将其展开:
$ dir=outer
$ bash -c "dir=inner; echo $dir"
outer
$ bash -c 'dir=inner; echo $dir'
inner
这两个公式都不是真正正确的,因为内部shell看到了一个不带引号的参数扩展,这可能导致不必要的分词和文件名扩展。通常,我们将使用的版本为:
bash -c 'dir=inner; echo "$dir"'
(在本例中,由于双引号位于单引号内,因此它们也被外壳视为普通字符,因此它们被传递到内部外壳。)
find-exec bash-c
的问题之一是通过find-exec
插入命令行的文件名按原样插入。这允许将精心编制的文件名用作文件名
为了避免这种情况,我们通常利用bash-c
还允许我们将位置参数传递给shell这一事实。在要解释的命令之后,bash-c
的参数被分配给$0
、$1
,依此类推。由于$0
不是一个真正的位置参数——它应该是脚本的名称——我们通常在命令参数之后和真正的位置参数之前放置一个伪参数(\
,在下面的示例中)。因此,我们将以这样的方式结束:
find ... -exec bash -c 'echo "$1"' _ {} \;
在这里,我仔细地引用了命令行参数,以便按原样传递它;在命令行参数中,我双引号引用参数扩展,这样空格和星号就不会引起任何问题,然后我得到find-exec
将文件名作为第三个参数传递给bash-c
,在那里它将变成$1
。我希望一切都清楚了
因此,为了回到原始问题,我们可以应用上述模式。但我要做一个小小的改变;我不再使用basename
查找文件名的最后一个组件,而是使用稍微神秘的shell语法来删除变量的前缀${var##*/}
获取$var
的值,然后删除与模式匹配的最长前缀*/
。(单个#
可能是最短的匹配。)最长的前缀匹配*/
是整个目录路径,因为它延伸到最后一个/
;删除后剩下的就是basename
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' _ {} \;
多么令人惊讶的答案。。。非常感谢你!