如何使用cp命令、变量和括号从不同目录复制多个文件?

4
我的问题与如何使用cp从不同目录复制多个文件?非常相似。
我不想使用显式循环。这是我所做的:
$ FILES_TOOLS="fastboot,fastboot-HW.sh"
$ cp $HOME/tools/{$FILES_TOOLS} $TOP_DIR/removeme
cp: cannot stat `/home/johndoe/tools/{fastboot,fastboot-HW.sh}': No such file or directory

文件已存在且目标有效,原因是:
$ cp $HOME/tools/{fastboot,fastboot-HW.sh} $TOP_DIR/removeme
$ echo $?
0
  • 我试图从FILES_TOOLS中删除双引号,但没有成功。
  • 我试图对 {...} 进行引用和双引号,但没有成功。
  • 我试图反斜杠转义括号,但没有成功。
  • 我猜这是当shell扩展实际发生时的问题。
3个回答

2

本答案仅限于bash。

cp命令前加上echo,以查看其转换后的内容:

echo cp $HOME/tools/{$FILES_TOOLS} $TOP_DIR/removeme

您需要在子shell中插入eval才能使其正常工作:
cp $( eval echo $HOME/tools/{$FILES_TOOLS} ) $TOP_DIR/removeme

1
只要花括号中的内容是文字,您可以使用花括号扩展来填充数组,以获得要复制的文件的完整路径名,然后在cp命令中展开数组的内容。
$ FILES_TOOLS=( $HOME/tools/{fastboot,fastboot-HW.sh} )
$ cp "${FILES_TOOLS[@]}" $TOP_DIR/removeme

更新:我意识到您可能有将基本名称单独放在变量中的原因。这里是另一种基于数组的解决方案,它允许您在不使用显式循环的情况下为数组的每个元素添加前缀路径:
$ FILES_TOOLS=( fastboot fastboot-HW.sh )
$ cp "${FILES_TOOLS[@]/#/$HOME/tools/}" $TOP_DIR/removeme

在这种情况下,您使用模式替换运算符将每个数组元素开头的空字符串替换为目录名称。

周五晚上太多括号了...我会静静地阅读这篇文章。谢谢。 - m-ric

1
我猜这是一个关于shell扩展何时实际发生的问题。
是的。不同的shell在变量扩展方面有不同的大括号扩展规则。你的方法在ksh中可行,但在zsh或bash中不可行。{1..$n}在ksh和zsh中可行,但在bash中不可行。在bash中,变量扩展总是在大括号扩展之后发生。
在bash中,最接近你想要的是使用eval。

确实很好了解这些Shell之间的区别! - m-ric
Bash在这方面完全独一无二。即使zsh在整理之前也执行花括号(序列)展开,而所有支持它的ksh和csh都是如此(mksh具有相同的展开顺序,但不支持序列展开)。当然,这也有很大的劣势。就我个人而言,我更喜欢Bash的行为。 - ormaaj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接