Как разделить команду оболочки на несколько строк при использовании оператора IF?


386

Как разделить команду на несколько строк в оболочке, если команда является частью ifоператора?

Это работает:

if ! fab --fabfile=.deploy/fabfile.py --forward-agent --disable-known-hosts deploy:$target; then rc=1                                                                       
fi

Это не работает:

# does not work:
if ! fab --fabfile=.deploy/fabfile.py \ 
  --forward-agent \
  --disable-known-hosts deploy:$target; then   
  rc=1
fi

Вместо выполнения всей команды я получаю:

./script.sh: line 73: --forward-agent: command not found

Что еще более важно, чего не хватает в моем понимании Bash, которое поможет мне понять эту и подобные проблемы в будущем?


2
В чем ошибка? Я могу выполнить $ if ! cp -n log/server1.log \ > .; then echo no copy; fiбез ошибок, с новой строкой после\
— Miserable Variable

16
Есть ли у вас пробелы после обратной косой черты в терминале \ ? Их довольно сложно увидеть. Если вы это сделаете, вы можете посмотреть, можете ли вы сделать так, чтобы ваш редактор убрал завершающие пробелы или сделал их более заметными.
— мсв

10
Да, это были пробелы после обратной косой черты терминала. Полностью. Спасибо.
— Дмитрий Минковский

И да, извините, я должен был опубликовать «ошибку» (неожиданный результат)! Виноват! Редактирование сейчас.
— Дмитрий Минковский

Каково было ваше понимание? Это тоже не часть вопроса.
— Хакре

Ответы:


569

Продолжение строки не будет выполнено, если у вас есть пробелы (пробелы или символы табуляции) после обратной косой черты и до новой строки. Без таких пробелов ваш пример отлично работает для меня:

$ cat test.sh
if ! fab --fabfile=.deploy/fabfile.py \
   --forward-agent \
   --disable-known-hosts deploy:$target; then
     echo failed
else
     echo succeeded
fi

$ alias fab=true; . ./test.sh
succeeded
$ alias fab=false; . ./test.sh
failed

Некоторая деталь продвигается из комментариев: обратная косая черта продолжения строки в оболочке на самом деле не является особым случаем; это просто пример общего правила, согласно которому обратная косая черта "заключает в кавычки" непосредственно следующий за ним символ, предотвращая любую специальную обработку, которой он обычно подвергается. В этом случае следующий символ - это новая строка, и предотвращаемая специальная обработка завершает команду. Обычно заключенный в кавычки символ включается буквально в команду; символ новой строки с обратной косой чертой удаляется полностью. Но в остальном механизм тот же. И обратная косая черта указывает только следующий сразу за ним символ; если этот символ - пробел или табуляция, вы просто получаете цитируемый пробел или табуляцию, и любой последующий символ новой строки остается без кавычек.


5
Марк, ты знаешь, у меня, должно быть, были пробелы. Я могу воспроизвести ошибку только при добавлении пробелов после `s. For example, when adding one after the first `, я получаю ./soundops: line 73: --forward-agent: command not found. Мои проблемы были в том, что я не понял эту ошибку. Почему наличие пробела приводит к этой ошибке? Пробел + \n"отрицает" `` и отделяет команду?
— Дмитрий Минковский

84
Обратная косая черта перед новой строкой предотвращает завершение команды новой строкой. Но так же, как специальные escape-последовательности, такие как \ n, работают только с обратной косой чертой и n, обратная косая черта-newline работает только с обратной косой чертой и новой строкой.
— Марк Рид

19
Хахаха вау, конечно, это имеет смысл. Никогда такого не видел. Открывающий глаза, но такой простой: это просто экранированный символ новой строки. Я ненавижу невидимых персонажей. Они имели бы для меня гораздо больше смысла, если бы все они были просто видны. Спасибо!
— Дмитрий Минковский

7
В большинстве редакторов вы можете сделать видимыми эти невидимые символы.
— lucasvc

1
Обратная косая черта и новая строка удаляются из действующей командной строки, но все пробелы в следующей строке сохраняются. Так что, проблема это или нет, зависит от того, будут ли пробелы в этой точке в однострочной команде.
— Марк Рид

52

Для пользователей Windows / WSL / Cygwin и т. Д .:

Удостоверьтесь, что ваши строки заканчиваются стандартным переводом строки Unix, т.е. только \n(LF).

Использование окончания строки в Windows \r\n(CRLF) приведет к разрыву строки.


Это связано с тем, что \в конце строки с окончанием строки Windows это означает \ \r \n.
Как правильно объясняет Марк, выше:

Продолжение строки не будет выполнено, если после обратной косой черты и до новой строки появятся пробелы.

Это включает в себя не только space ( ) или tabs ( \t), но и возврат каретки ( \r).


1
Это устраняет проблему, созданную при создании сценария в Windows и последующем его использовании в Windows bash (например, bash -c MyShellScript.sh, где MyShellScript.sh был создан в редакторе Windows). Вы должны сохранить MyShellScript.sh в формате UNIX, возможно, используя notepad ++.
— BSalita
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.