Как разделить команду оболочки на несколько строк при использовании оператора 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).

Czechnology
источник
1
Это устраняет проблему, созданную при создании сценария в Windows и последующем его использовании в Windows bash (например, bash -c MyShellScript.sh, где MyShellScript.sh был создан в редакторе Windows). Вы должны сохранить MyShellScript.sh в формате UNIX, возможно, используя notepad ++.
BSalita