sh 替代 bash cp {file,file}

sh 替代 bash cp {file,file}

在脚本中,如果我将其放在#!/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值。由于它是directorycp贝壳而不是cp扩展的命令dir,这将不起作用。)

方法 3:cdig 到前缀

如果你的脚本在执行此操作后没有执行任何其他操作,或者当前目录对于后续命令来说并不重要,那么如果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

相关内容