通过管道查找 xargs 在终端中有效,但在 shell 脚本中无效

通过管道查找 xargs 在终端中有效,但在 shell 脚本中无效

我正在尝试编写一个 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 在运行命令的字符串中以不同的方式对待管道。我通过更改线路解决了这个问题$cmdeval "$cmd"现在效果很好!

请注意,eval可能会导致代码注入问题,但这与此特定脚本无关。

答案2

您对将列表加载到命令有一个好主意,但是还有更好的方法来组合变量和命令。

@KamilMaciorowski 在这里提供了一些很好的背景信息,但您可能仍在寻找更明确的答案。通过阅读此处的更多内容,您可以看到一个很好的示例,用于将printf数组格式化为命令。find

在您的情况下,这将是这样的:

find ./* -maxdepth 0 $(printf "! -name %s " $EXCLUDED_FILES) -exec cp -r {} $TARGET_DIR \;

相关内容