我正在尝试编写一个 Bash shell 脚本,它将当前目录中的所有文件(除了一些例外)复制到另一个目录中。该脚本构建一个命令,将其存储在变量中,然后运行它。这是令人困惑的部分:当它构建的命令在 shell 脚本中运行时,它会失败并显示消息“find: paths must precede expression: `|xargs'
如果我删除 之前的空格|
,我会看到 ” find: unknown predicate `-i'
。但是当我echo
命令它构建并运行它时,它工作得很好!更奇怪的是,echo "$cmd"|bash
失败并显示相同的错误消息!
剧本 (synchronize.sh
):
#! /bin/bash
EXCLUDED_FILES=(folder1 file.txt synchronize.sh)
FLAGS='-r'
PROJECT_NAME=project
TARGET_DIR=$HOME/Documents/IDE/$PROJECT_NAME/assets
cmd='find ./* -maxdepth 0'
cmd_end="|xargs -i cp -r {} -t $TARGET_DIR"
for file in ${EXCLUDED_FILES[@]}
do
cmd+=" ! -name \"$file\""
done
cmd+=$cmd_end
$cmd #Running the command directly fails
#echo $cmd #Yet copying and pasting the output of this command will work just fine
#echo "$cmd"|bash #Though this inexplicably fails, with the same message as just $cmd
所有文件或文件夹的名称中都没有空格,也没有任何特殊字符(下划线和句点除外)。
答案1
因此,在 @KamilMaciorowski 链接的答案中,我了解到 Bash 在运行命令的字符串中以不同的方式对待管道。我通过更改线路解决了这个问题$cmd
,eval "$cmd"
现在效果很好!
请注意,eval
可能会导致代码注入问题,但这与此特定脚本无关。
答案2
您对将列表加载到命令有一个好主意,但是还有更好的方法来组合变量和命令。
@KamilMaciorowski 在这里提供了一些很好的背景信息,但您可能仍在寻找更明确的答案。通过阅读此处的更多内容,您可以看到一个很好的示例,用于将printf
数组格式化为命令。find
在您的情况下,这将是这样的:
find ./* -maxdepth 0 $(printf "! -name %s " $EXCLUDED_FILES) -exec cp -r {} $TARGET_DIR \;