Запуск нескольких команд в одной строке в оболочке

389

Скажем, у меня есть файл, /templates/appleи я хочу

  1. положить его в двух разных местах, а затем
  2. удалить оригинал

Итак, /templates/appleбудут скопированы в /templates/usedAND, /templates/inuse а затем после этого я хотел бы удалить оригинал.

Это cpлучший способ сделать это, а затем rm? Или есть лучший способ?

Я хочу сделать все это в одну строку, поэтому я думаю, что это будет выглядеть примерно так:

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

Это правильный синтаксис?

Джон Рединс
источник

Ответы:

795

Вы используете |(pipe) для направления вывода команды в другую команду. То, что вы ищете, это &&оператор для выполнения следующей команды, только если предыдущая преуспела:

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

Или

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

Подводя итог (не исчерпывающе) командных операторов / разделителей bash:

  • |передает (конвейеры) стандартный вывод ( stdout) одной команды на стандартный ввод другой. Обратите внимание, чтоstderr все еще входит в пункт назначения по умолчанию, каким бы он ни был.
  • |&трубы stdoutиstderr одну команду в стандартный ввод другой. Очень полезно, доступно в bash версии 4 и выше.
  • && выполняет правую команду && только если предыдущая преуспела.
  • || выполняет правую команду || только в том случае, если предыдущая не удалась.
  • ;выполняет правую команду ;всегда независимо от того, была ли предыдущая команда успешной или неудачной. Если set -eранее не был вызван, что приводит bashк сбою при ошибке.
Максим Егорушкин
источник
6
Upvoted. Официальная документация gnu.org/software/bash/manual/bash.html#Lists
flow2k
78

Почему бы не cpк месту 1, тоmv в место 2. Это заботится о «удалении» оригинала.

И нет, это не правильный синтаксис. |используется для «передачи» вывода из одной программы и превращения его во ввод для следующей программы. То, что вы хотите ;, это разделить несколько команд.

cp file1 file2 ; cp file1 file3 ; rm file1

Если вам требуется, чтобы отдельные команды ДОЛЖНЫ были выполнены успешно, прежде чем могут быть запущены следующие, вы должны использовать &&вместо этого:

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

Таким образом, если какая-либо из cpкоманд не rmбудет выполнена , команда не будет запущена.

Марк Б
источник
10

Обратите внимание, что cp A B; rm Aэто точно mv A B. Это также будет быстрее, поскольку вам не нужно фактически копировать байты (при условии, что место назначения находится в той же файловой системе), просто переименуйте файл. Так ты хочешьcp A B; mv A C

Гленн Джекман
источник
7

Другим вариантом является ввод 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+Enterили Esc+EnterвместоCtrl+V Ctrl+J

Эяль Левин
источник
3

Попробуй это..

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

Питер
источник
2

Использование труб мне кажется странным. В любом случае вы должны использовать логический andоператор Bash:

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

Если cpкоманды не пройдены, команда rmне будет выполнена.

Или вы можете сделать более сложную командную строку, используя forцикл и cmp.

Renaud
источник