Я плохо знаком со сценариями Bash и Linux. На работе я видел сценарии Bash с конструкциями, подобными этому:
mkdir build && cd build && touch blank.txt
Или:
mkdir build; cd build; touch blank.txt
Или даже экзотическое:
COMMAND="mkdir build && cd build && touch blank.txt"
eval ${COMMAND}
Последний пример дает один возможный пример использования, где одна строка могла быть полезной, но обычно следующее легче считать, и (по крайней мере, для меня) позволяет Вам визуально отлаживать сценарий:
mkdir build
cd build
touch blank.txt
Там технические преимущества - к зубрежке все на одной строке?
mkdir build && cd build && touch blank.txt
В Bash (и некоторые другие оболочки) &&
логическое и, что означает - если предыдущая команда возвратит true, то следующая команда будет выполняться. Там также логично или ||
. Например, можно объединить эти две опции в одном операторе:
mkdir /tmp/abc/123 && echo 'the dir is created' || echo "the dir isn't created"
Отметьте, конструкция cmd_1 && cmd_2 || comd_3
не замена if; then; else
оператор, потому что, неважно, какая из предыдущих команд возвращает false, cmd_3
будет выполняться. Таким образом, необходимо быть осторожны относительно обстоятельств, при которых Вы используете его. Вот пример:
$ true && false || echo success
success
$ false && true || echo success
success
$ false && false || echo success
success
Как правило, эмпирическое правило, обычно, когда я использую cd
команда в рамках сценария, я помещаю тест, успешно ли изменение каталога: cd somewhere/ || exit
. Более надлежащий тест предложен @dessert: if ! cd dir; then exit 1; fi
. Но во всех случаях как защита отказа сценария лучше использовать set -e
опция, поскольку это показывают в ответе @mrks'.
mkdir build; cd build; touch blank.txt
;
разделитель строки, и он используется, когда немного разделенных команд записаны в одной строке.
Отметьте когда ;
или &&
и ||
используются это не обязательно для записи команд в на строке - это проиллюстрировано в рамках ответа @allo.
Вообще, IMO, нет никакого специального технического преимущества/различия между записью команд в одной или в отдельных строках.
COMMAND="mkdir build && cd build && touch blank.txt"
eval ${COMMAND}
Здесь одна или несколько команд (и их аргументы) сгруппированы как значение переменной, и затем эта переменная (аргумент) преобразовывается в команду справкой eval
. Таким образом Вы сможете изменить команду, которая будет выполняться многократно в рамках некоторого сценария путем изменения его только в одном месте.
Скажем, необходимо изменить путь в который файл blank.txt
создается, например, можно изменить соответствующую строку способом как это:
COMMAND="mkdir build && cd build && echo 'test' > blank.txt"
Фактическое eval
преимущество перед использованием alias
когда существуют перенаправления, каналы, логические операторы, и т.д. используются. В большинстве случаев можно использовать functions
вместо eval
когда alias
не применимо. Также в случае, если переменная содержит только единственную команду, т.е. CMD="cat"
, нам не нужно eval
, потому что разделенный на мир Bash расширится "$CMD" "$file1" "$file2"
правильно.
Предыдущая версия этого раздела, обсужденного в рамках комментариев, доступна здесь.
Ответы до сих пор обращаются к тому, что происходит/как, это работает, но я думаю, что Вы спрашивали "почему"
Основная "Причина" сделать (для меня) вместо того, чтобы ввести их на трех строках случается так, что иногда команды занимают время (Иногда минуты), и Вы не хотите болтаться в течение всего времени.
Например, я мог бы создать &&
развернуться &&
запустите мое приложение затем выходят на ланч. Процесс мог занять 15 минут для завершения. Однако, так как я использовал &&
, это не развернется, если сборка перестанет работать - так, чтобы работы.
Опережающий ввод является альтернативой, но это сомнительно, Вы не смогли видеть то, что Вы вводите (и поэтому делаете ошибки), или программа могла бы съесть опережающий ввод (Спасибо, чаши Грааля!). Затем Вы возвращаетесь из ланча и узнаете, что у Вас все еще есть две длинноватых задачи начаться из-за опечатки.
Другая альтернатива пишет маленький сценарий или псевдоним. Не плохая идея, но не позволяет столько же гибкости, как я могу:
stop && build && test && deploy && start
или я могу просто:
stop && start
Или любое количество других комбинаций, которые быстро загрязнили бы сценарий наборами флагов.
Даже если Вы действительно запишете сценарий, то Вы, вероятно, интегрируете его с другими сценариями с &&
.
Объединение команд на Linux может быть очень полезным.
Хороший пример может перезапускать интерфейс удаленной сети через ssh (при изменении конфигурации сети или чего-то...).
ifdown eth0 && ifup eth0
Это может препятствовать тому, чтобы Вы шли физически в сервер, для перевода в рабочее состояние интерфейса Вы где первоначально ssh'ing к. (Вы не сможете, выполняются ifup eth0
если ifdown eth0
выполняется один.)
Для понимания, почему, мы также должны понять то, что делается. Сценарии последовательны. В Вашем последнем примере:
mkdir build
cd build
touch blank.txt
cd build
будет выполняться независимо от mkdir build
следование или нет. Конечно, если mkdir fails
, Вы будете видеть ошибку от cd
.
mkdir build; cd build; touch blank.txt
последовательный список. Это может думаться как по существу то же как несколько строк сценария. Грамматика Shell будет рассматривать это немного по-другому, но результатом будет точно то же как выше. Снова, команды выполняются независимо от того, успешно выполнилось ли предыдущее.
Наконец, существует
mkdir build && cd build && touch blank.txt
который является И списки - последовательность одного или нескольких конвейеров (или команды) разделен &&
оператор. Команды в таком списке выполняются с левой ассоциативностью. Это означает, оболочка будет продолжать брать две команды/конвейера, разделенные &&
, выполните тот слева сначала и выполните тот справа, только если оставленный, за которым следуют (возвратил нулевой статус выхода).
В этом примере, что произойдет?
mkdir build
сначала. cd build
будет работать... && touch blank.txt
. Действительно наполнял слева от &&
успешно выполниться? Если да, выполненный touch blank.txt
.Последовательный список mkdir build; cd build; touch blank.txt
имеет смысл, когда мы соглашаемся с одним из сбоя команд. Предположим mkdir build
уже существует. Мы все еще хотим cd
в build/
каталог и touch blank.txt
. Конечно, недостаток здесь - то, что существует возможность непреднамеренного результата. Что, если build
имеет не выполняют набор битов, и вот почему cd build
сбои? touch blank.txt
произойдет в нашем текущем рабочем каталоге вместо намеченного build/
.
Теперь рассмотрите mkdir build && cd build && touch blank.txt
. Это несколько более логично, хотя имеет его собственные ловушки. Если build
уже существует, вероятно, кто-то уже сделал touch blank.txt
также, таким образом, мы не можем хотеть делать touch blank.txt
снова, поскольку это изменит метку времени доступа на нем, которая является чем-то, что не могло бы быть желательно.
Размещение команд на той же строке зависит от цели команд и чего Вы пытаетесь достигнуть. Последовательные списки могут упростить вывод, поскольку оболочка не вновь отобразит подсказку, пока команды не закончились. И список допускает условное выполнение команд и может предотвратить выполнение ненужных команд. Нижняя строка - то, что пользователь должен знать различия и что выбрать как правильный инструмент для задачи.
Другая причина могла бы быть в том, как сценарий оказался: Для технических пользователей весьма обычно создать очень длинные интерактивные командные строки, неоднократно расширяясь и тестируя их, пока они не работают, как желаемый, затем вставляя результат в текстовый файл и хлопая a #!/bin/bash
заголовок по нему. Иногда несколько сегментов сценария развиты тем методом.
Долго конструкции строки, которые начинаются for i in
, grep | cut | sed | xargs
цепочки, интенсивное использование &&
и ||
, $(cat something)
конструкции часто показательны из таких источников.
Когда мы пишем, что ответы здесь в Спрашивают Ubuntu, полезно поместить их в одну строку, которую люди могут вырезать и вставить в их легче терминал. Например:
$ CurrDir=$PWD ; cd /bin ; ls -la dd ; cd "$CurrDir"
-rwxr-xr-x 1 root root 72632 Mar 2 2017 dd
Как отмечалось ранее, Вы могли использовать &&
для того же эффекта, но если были ошибки выше Вас, мог бы закончиться на неправильном каталоге. В этом случае ;
предпочтительно для &&
это не тестируется на успех:
rick@alien:~/askubuntu$ CurrDir=$PWD && cd /bin && llllssss -la dd && cd "$CurrDir"
llllssss: command not found
rick@alien:/bin$
Существуют некоторые команды, где необходимо представить несколько строк в виде строки вместе. Один случай является сокращенным if
- команды -fi
который должен быть одной строкой. Например:
$ [[ 2 -eq 2 ]] && { echo 2 equals 2 ; echo setting three to 3 ; three=3 ; }
2 equals 2
setting three to 3
Там технические преимущества - к зубрежке все на одной строке?
Это - только вопрос стиля. Нет технических преимуществ.
Я думаю, что другие объяснили, что является различиями в этих трех строках вполне хорошо, но отмечает, что это не означает, что у Вас должны быть они на одной строке.
foo &&
bar
делает то же как foo && bar
. Все еще необходимо быть осторожными, как
foo
&& bar
не делает того же, но выполняет нечто и затем производит синтаксическую ошибку. Общее правило в большинстве случаев: Когда оболочка знает от синтаксиса, что Ваша строка не завершена, это позволяет Вам продолжать следующую строку.
Когда первая строка может быть выполнена, как это, затем это будет выполняться (и следующая строка может или не может быть синтаксической ошибкой, потому что первый отсутствует).
Когда Вы все еще хотите, чтобы Ваш сценарий был более читаемым, можно выйти из символа новой строки как это
foo \
&& bar
Удостоверьтесь, что нет никакого пробела после \
символ, как это должно прибыть непосредственно перед символом новой строки.
Многие ответы здесь говорят о безопасности, например, "Что происходит если cd
сбои"?
При объединении команд такой как cd foo && rm *
решает ту проблему, существует намного лучший способ сделать это:
Возьмите эту структуру папок:
.
./foo
./foo/bar
./foo2
./foo2/bar2
./test.sh
./do_not_delete_me
и следующий сценарий:
find .
cd notexisting
rm *
cd ../foo2
rm *
cd ..
find .
Как notexisting
не существует, rm *
будет работать в .
и удалите do_not_delete_me
.
Однако, если Вы запускаете сценарий с set -e
, это прервется с первой неудавшейся командой:
./test.sh: line 4: cd: notexisting: No such file or directory
Как упомянуто в комментариях, имеет смысл включать его в хижину: #!/bin/bash -e
.