我正在研究用Shell编写的部署脚本,该脚本将在Linux服务器上执行。部分要求是,源端的某些文件夹会聚合到目标端的单个文件夹中。这些不会随着项目的历史而改变,因此我为它们创建了一个关联数组,如下所示:
declare -A DIRSET
DIRSET["Content_A"]='/contents'
DIRSET["Content_B"]='/contents'
DIRSET["Templates"]='/templates'
DIRSET["Other Content"]='/templates'
此关联数组用于将源目录映射到目标目录。稍后,在我的脚本中,我将使用类似于以下的循环遍历这些内容:
for key in "${!DIRSET[@]}"
do
SUBDIR=${DIRSET[$key]}
find . -type d -name "'$key'" | while read line; do
if ls -1qA "${line}/" | grep -q
then
# to strip away './'
OLDDIR=${line:2:${#line}}
SUBPATH="${PROJ_ROOT}/AggregateFolder/${SUBDIR}"
rsync -rvic -e "ssh some/.ssh/dir" "${OLDDIR}/" "${SUBPATH}"
fi
done
此循环使用“ find”查找要聚合的目录,然后将其输入“ rsync”命令。 “模板”中的内容以某种方式使它变得完整,而“其他内容”中的内容则没有。即使该目录存在,“ find”命令似乎也不会返回任何结果。
奇怪的是,当我打开外壳,内联声明变量并执行与上述循环段相同的“查找”时,我得到了结果。我试图从“键”周围删除单引号,并将它们放在关联数组键定义周围,如下所示:
DIRSET["'Other Content'"]='/templates'
...
find . -type d -name "$key"
但是,这也不会产生“查找”结果。我将命令放在脚本的回显中,以确保变量按预期方式传递到命令中:
echo "find . -type d -name $key"
find . -type d -name "$key"
但是输出最终是这样的,其中循环中的所有find命令都不起作用:
...
find . -type d -name Templates
find . -type d -name 'Other Content'
请注意,如果我在关联数组键或其“ $ key”引用周围没有单引号,则在shell尝试将我的字符串解释为一系列以空格分隔的命令时,会出现错误。
是否有任何原因可以使“ find”命令以一种内联方式运行,但在执行的脚本中以不同方式运行?感觉就像我在寻找鼻子前的东西。一些外部的观点将不胜感激。
注意:源系统和目标系统都具有Bash 4版本(分别为4.4和4.3),因此应允许使用关联数组。
答案 0 :(得分:1)
我认为根本的误解是在shell命令字符串和程序调用之间。
这样的shell命令字符串:
find . -type d -name 'Other Content'
将变成一个参数列表,并传递给find
,如下所示:
find
,.
,-type
,d
,-name
,Other Content
由这个参数列表决定find
的作用。这就是真理的源头。任何导致该参数列表的命令字符串都将以您想要的方式运行find
。任何导致不同参数列表的命令字符串都将执行其他操作。因此,它正在构建您应该努力的参数列表。
试图获取echo
以打印shell命令字符串没有什么价值,就像您不会通过显示console.log(..)
或print(..)
来尝试编写JS或Python一样您要运行的语句。
要更准确地了解结果参数,可以使用printf
:
$ printf 'Argument: <%s>\n' find . -type d -name 'Other Content'
Argument: <find>
Argument: <.>
Argument: <-type>
Argument: <d>
Argument: <-name>
Argument: <Other Content>
如果要从变量的内容中获得相同的结果,则应确保命令输出相同的内容。就您而言,不是:
$ printf 'Argument: <%s>\n' find . -type d -name "'$key'"
Argument: <find>
Argument: <.>
Argument: <-type>
Argument: <d>
Argument: <-name>
Argument: <'Other Content'> # Different argument, so different result
同样的技术显然也可以证明您的其他尝试是如何失败的:
$ key="'Other Content'"
$ printf 'Argument: <%s>\n' ... -name $key
Argument: <...>
Argument: <-name>
Argument: <'Other> # Both extra apostrophes
Argument: <Content'> # and bad splitting
当两个printf
语句生成相同的参数列表时(仅在您的情况下使用"$key"
),就可以删除printf '..'
位并运行find
命令直接。