在脚本中,如果我将其放在#!/bin/bash
顶部,这将正常工作:
cp directory/{foo,bar} destination
但是,使用 sh 时,会出现错误“没有这样的文件或目录”。在 sh 中,还有其他方法可以用一个命令实现相同的最终目标吗?
答案1
正如你所观察到的,并不是所有的 shell 都支持括号扩展。
方法一:两条单独的路径(即写两次前缀)
如果您的目标实际上只是用一个命令完成,那么一个简单的方法是:
cp directory/file1 directory/file2 destination
这cp
命令支持多个源参数,后跟一个目标参数。事实上,这就是 Bash 中为您工作的命令所发生的情况。Bash 执行括号扩展,将您使用的命令转换为上面显示的命令。也就是说,当您cp directory/{file1,file2} destination
在 Bash 中运行时,该cp
命令永远不会看到任何花括号。
这样的命令简单易懂。我建议考虑一下。
方法 2:前缀变量
但如果你的目标是避免重复您可能不想这样做,尤其是当directory
路径很长时。毕竟,如果您稍后需要在脚本中编辑路径,则必须对两个路径都进行更改。
你可以存储directory
(或者其他任何可能更长的路径)在shell 变量:
dir='directory'
cp "$dir/file1" "$dir/file2" destination
$dir
是参数扩展。shell 将其替换为变量中保存的值dir
。使用参数扩展时,您不应省略这双引号--除非是极少数情况你要的那个场分裂和通配符要执行的操作。(这也适用于 Bash。)
这是两个命令,但如果你的实际目标是避免重复,那么这可能就是你想要的。你可以写
dir='directory'; cp "$dir/file1" "$dir/file2" destination
使其成为“一个命令”,但这并不短,而且可读性也较差。
(请注意,您不能简单地删除;
那里。这样做的结果将是一个格式正确的命令,但它不会执行您想要的操作。它将运行该cp
命令,传递一个环境变量调用该命令的环境并传入dir
值。由于它是directory
cp
贝壳而不是cp
扩展的命令dir
,这将不起作用。)
方法 3:cd
ig 到前缀
如果你的脚本在执行此操作后没有执行任何其他操作,或者当前目录对于后续命令来说并不重要,那么如果destination
是绝对路径, 您可以使用:
cd directory
cp file1 file2 destination
但我不建议在脚本中这样做,除非你的脚本执行的后续操作从该目录运行会更好,或者从该目录运行时可以写得更简洁或更简单。除非脚本运行的目录是有意义的脚本的目的,依赖它可能使脚本更难推理;此外,如果命令cd
成功但cp
命令失败,则产生的错误消息可能不完全说明问题。相反,我提到了cd
源目录的技术,因为它是一种有用的模式交互的外壳的使用。
(作为Hannu 指出, 你可以将任意数量的命令放在一起(
)
在子壳以及对 shell 环境的更改(包括 的效果cd
)在命令运行后不会保留。这是一种广泛使用的技巧,我没有提到它,这是一个重大的疏漏。但请注意,这并不能减轻与相对路径为了destination
。)
请注意,如果cd
命令失败,其他命令通常仍会运行。这可能会复制您不想复制的不同文件(如果脚本运行的目录中有其他同名文件)或产生令人困惑的错误消息。因此您可能更喜欢:
cd directory && cp file1 file2 destination
导致&&
第二条命令运行仅当第一个命令成功时。请注意,这仍然不会撤消运行第一个命令的效果。整个程序运行完毕后,您仍将处于 中directory
,除非您使用 将其运行在子 shell 中(
)
。
答案2
编辑 1:问题修改后,第一个替代方案不再有效,第二个替代方案被修改为“file1 file2”-->“foo bar”,并扩展了额外的示例。
它对我sh
有用
cp directory/file[12] destination
它也应该适合你。
更高级的替代方法是 for 循环
for i in foo bar;do cp directory/"$i" destination;done
这很容易扩展,例如
for i in foo bar more files;do cp directory/"$i" destination;done
或者
for i in dir1/foo* /dir2/bar*;do cp "$i" destination;done
或者
for i in dir1/* /dir2/*;do cp "$i" destination;done
编辑 2:与其使用高级构造,cp
不如学习并开始使用rsync
,这是一个具有许多内置功能的工具,可以进行本地或通过网络复制并指定要复制的内容。
看man rsync