在脚本中,如果我放在#!/bin/bash顶部,这将正常工作:
cp directory/{foo,bar} destination
但是,使用 sh,这将给出错误“没有这样的文件或目录”。在 sh 中,是否有另一种方法可以通过一个命令实现相同的最终目标?
正如您所观察到的,并非所有 shell 都支持大括号扩展。
如果你的目标真的只是在一个命令中完成,一个简单的方法是:
cp directory/file1 directory/file2 destination
Run Code Online (Sandbox Code Playgroud)
该cp命令支持多个源参数,后跟一个目标参数。事实上,这就是在 Bash 中为您工作的命令所发生的情况。Bash 执行大括号扩展,它将您一直使用的命令转换为上面显示的命令。也就是说,当您cp directory/{file1,file2} destination在 Bash 中运行时,该cp命令永远不会看到任何花括号。
这样的命令简单易懂。我建议考虑一下。
但是,如果您的目标是避免重复自己,那么您可能不想那样做,尤其是如果directory实际上是一条很长的路。毕竟,如果您稍后必须在脚本中编辑路径,则必须对两次出现的路径进行更改。
您可以directory在shell 变量中存储(或其他任何东西,大概是更长的路径):
dir='directory'
cp "$dir/file1" "$dir/file2" destination
Run Code Online (Sandbox Code Playgroud)
$dir是参数扩展。Shell 将其替换为变量中保存的值dir。当使用参数扩展,你不应该忽略的双引号-除了在极少数情况下,你想场分裂和通配符进行。(这也适用于 Bash。)
这是两个命令,但如果您的实际目标是避免重复自己,那可能就是您想要的。你可以写
dir='directory'; cp "$dir/file1" "$dir/file2" destination
Run Code Online (Sandbox Code Playgroud)
使其成为“一个命令”,但这并不短,而且可读性稍差。
(请注意,您不能简单地删除;那里。这样做的结果将是一个格式良好的命令,但它不会执行您想要的操作。它会运行该cp命令,将使用该值调用的环境变量传递到命令的环境中。因为它是外壳而不是命令,所以扩展,这行不通。)dirdirectorycpcpdir
cdig到前缀如果您的脚本在执行此操作后没有执行任何其他操作,或者对于后续命令当前目录是什么并不重要,那么ifdestination是绝对路径,您可以使用:
cd directory
cp file1 file2 destination
Run Code Online (Sandbox Code Playgroud)
但我不建议将其用于脚本编写,除非您的脚本执行从该目录运行中受益的后续操作,或者在从该目录运行时可以更简洁或更简单地编写。除非运行脚本的目录对脚本的目的有意义,否则依赖它会使脚本更难推理;此外,如果cd命令成功但cp命令失败,则产生的错误消息可能无法完全说明。相反,我提到了cding 到源目录的技术,因为它是交互式shell 使用的有用模式。
(正如Hannu 所指出的,您可以将任意数量的命令放在一起( )以在子 shell 中运行它们,并且对 shell 环境的更改,包括 的影响cd,在命令运行后不会持续存在。这是一种广泛有用的技术,这是一个实质性的疏忽,我没有提到它。但要注意,这并不减轻与具有任何问题相对路径的destination。)
请注意,如果cd命令失败,其他命令通常仍会运行。这可能会复制您不想复制的不同文件(如果运行脚本的目录中有其他同名文件)或产生令人困惑的错误消息。所以你可能更喜欢:
cd directory && cp file1 file2 destination
Run Code Online (Sandbox Code Playgroud)
将&&导致第二命令来运行只有当第一个命令成功。请注意,这仍然不会撤消运行第一个命令的效果。整个事情运行后,你仍然会在directory,除非你在一个子shell运行它( )。