在shell中在一行中运行多个命令

假设我有一个文件/templates/apple,我想

  1. 放在两个不同的地方,然后
  2. 去掉原来的。
因此,/templates/apple将被复制到/templates/used/templates/inuse 然后,我想删除原来的。

cp是做到这一点的最好方法吗,然后是rm?还是有更好的办法?

我想在一行中完成这一切,所以我认为它看起来会像这样:

cp /templates/apple /templates/used | cp /templates/apple /templates/inuse | rm /templates/apple

这样的语法正确吗?

619255 次浏览

为什么不是cp到位置1,然后mv到位置2。这是为了“移除”原始文件。

不,这不是正确的语法。|用于“管道”一个程序的输出,并将其转换为下一个程序的输入。你需要的是;,它分离了多个命令。

cp file1 file2 ; cp file1 file3 ; rm file1

如果你要求单独的命令必须成功才能启动下一个命令,那么你可以使用&&代替:

cp file1 file2 && cp file1 file3 && rm file1

这样,如果cp命令中的任何一个失败,rm将不会运行。

试试这个. .

cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apple

你正在使用|(管道)将一个命令的输出导向另一个命令。你要找的是&&操作符,它只在前一个命令成功时执行下一个命令:

cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apple

cp /templates/apple /templates/used && mv /templates/apple /templates/inuse

(非详尽地)总结bash的命令操作符/分隔符:

  • |管道(pipelines)将一个命令的标准输出(stdout)转换为另一个命令的标准输入。注意,stderr仍然会进入它的默认目的地,不管它是什么。
  • __abc0将一个命令的stdoutstderr同时输送到另一个命令的标准输入中。非常有用,在bash版本4及更高版本中可用。
  • &&只在前一个命令成功时才执行&&的右命令。
  • ||只在前一个命令失败时执行||的右命令。
  • ;总是执行;的右命令,不管前一个命令是否成功。除非之前调用过set -e,这会导致bash在出现错误时失败。

使用管道对我来说似乎很奇怪。无论如何,你应该使用逻辑and Bash操作符:

$ cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apples

如果cp命令失败,rm将不会被执行。

或者,你可以使用for循环和cmp来创建一个更详细的命令行。

注意,cp A B; rm A就是mv A B。这也会更快,因为您不必实际复制字节(假设目标位于相同的文件系统上),只需重命名文件即可。所以你需要cp A B; mv A C

另一种选择是在每个命令的末尾键入Ctrl + V Ctrl + J

示例(用Ctrl + V Ctrl + J替换#):

$ echo 1#
echo 2#
echo 3

输出:

1
2
3

这将执行命令,不管之前的命令是否失败。

与:echo 1; echo 2; echo 3相同

如果你想停止执行失败的命令,除了最后一行,在每一行的末尾添加&&

示例(用Ctrl + V Ctrl + J替换#):

$ echo 1 &&#
failed-command &&#
echo 2

输出:

1
failed-command: command not found

zsh中,你也可以使用Alt + EnterEsc + Enter来代替Ctrl + V Ctrl + J