Почему мне нужно поместить «do» в той же строке, что и «for»?


28

1. Резюме

Я не понимаю, зачем мне правило E010 bashate .


2. Детали

Я использую Bashate для Linting .shфайлов. Правило E010:

делать не на той же линии, что и для

for bashate:

  • Правильный:

    #!/bin/bash
    for f in bash/*.sh; do
        sashacommand "$f"
    done
  • Ошибка:

    #!/bin/bash
    for f in bash/*.sh
        do sashacommand "$f"
    done

Есть ли веские аргументы, зачем мне forи doв одну строчку?


3. Не полезно

Я не могу найти ответ на свой вопрос в:

  1. Google
  2. Статьи о лучших практиках кодирования ( пример )
  3. Bashate документация . Я нахожу только :

    Набор правил, которые помогают поддерживать последовательность в блоках управления. Они игнорируются на длинных очередях, которые имеют продолжение, потому что развертывание, которое является «интересным»


3
Отступы do, безусловно, немного необычны, но for ... \ndo\n<indent>body...чрезвычайно распространены, и я бы даже оценил больше, чем for ... ; do. Это также жалуется на это?
— Майкл Гомер

20
bashateэто проверка стиля Стили по своей природе субъективны. Не используйте его, если вам не нравится стиль, который он навязывает. Вместо этого вы должны рассмотреть синтаксис / проверку ошибок как shellcheck .
— Мей

@ meuh, спасибо, я уже использую ShellCheck. мой вопрос: E010- только стиль правило или в некоторых случаях мне нужно для и сделать в одной и той же линии , не только по причинам стиля.
— Саша Черных

10
Там никогда не синтаксическая обязанность иметь для и делать на ту же строку в оболочке.
— Мей

1
@ Саша Черных Это не само по себе отступление, а отступ do. Это как отступы открывающей фигурной скобки ifи добавить код на ту же строку в языке , как C. Другого примера, если питон позволил это, было бы поставив :в ifотступе на следующую строке и добавление кода на ту же строку. Это будет отличать его от дополнительных линий в теле.
— JoL

Ответы:


60

Синтаксически следующие два фрагмента кода являются правильными и эквивалентными:

for f in bash/*.sh; do
    sashacommand "$f"
done
for f in bash/*.sh
    do sashacommand "$f"
done

Последнее можно было бы , возможно , можно сказать, будет труднее читать doнемного запутывает команды в теле цикла. Если цикл содержит несколько команд, а следующая команда находится на новой строке, запутывание будет дополнительно выделено:

for f in *
    do cmd1
    cmd2
done

... но помечать это как "ошибку" - ИМХО чье-то личное мнение, а не объективная истина.

В общем, почти любой ;может быть заменен на новую строку. И ;новая, и новая строка являются командными терминаторами. doэто ключевое слово, которое означает «здесь следует то, что нужно сделать (в этом forцикле)».

for f in *; do ...; done

такой же как

for f in *
do
   ...
done

и в качестве

for f in *; do
   ...
done

Причиной использования одного над другим является удобочитаемость и местные / личные стили стиля.


Личное мнение:

В заголовках цикла, которые очень длинные , я думаю, что может иметь смысл поставить doновую строку, как в

for i in animals people houses thoughts basketballs bees
do
    ...
done

или

for i in        \
    animals     \
    people      \
    houses      \
    thoughts    \
    basketballs \
    bees
do
    ...
done

То же самое относится к thenв ifзаявлении.

Но опять же, это сводится к личным предпочтениям стиля или к любому стилю кодирования, который использует ваша команда / проект.


Вы говорите: «В заголовках цикла, которые очень длинные, может иметь смысл поставить новую строку». Не могли бы вы указать причину этого? Учитывая, что за заголовком должен следовать do, я не вижу причины, по которой его размещение на следующей строке могло бы улучшить читаемость.
— Конрад Рудольф

3
@KonradRudolph Мой терминал имеет ширину 80 символов. Если список будет перенесен, я сделаю его набором непрерывных строк (как в моем последнем примере), если он будет почти перенесен, я поставлю do(или then) на отдельной строке (как в примере со второго по последний). Все это связано с личными предпочтениями. Мне не нравятся слишком длинные строки, отчасти потому, что мой терминал "всего" шириной 80 символов, а отчасти потому, что я думаю, что он выглядит неопрятно. Мне также трудно разбирать очень длинные строки на наличие ошибок.
— Кусалананда

1
Кажется ненужным постоянно указывать, что это мнение. Bashate - это руководство по стилю, поэтому оно основано на мнении.
— Бармар

4
@Barmar, обратите внимание, что в данном вопросе используются такие фразы, как «need to» и «rule», а readme-вызов bashate вызывает в doотдельной строке «error». Это довольно жесткие фразы, так что это действительно кажется , стоит того , чтобы указать на то , что, скорее, наоборот, так называемое «правило» на самом деле просто субъективное мнение.
— ilkkachu

2
@mtraceur Правильно, я не подвергаю сомнению личные предпочтения. Но имейте в виду, что ограничение на читаемость столбца, которое вы цитируете, не относится к коду. Это относится только к прозе. Движение глаз принципиально отличается для чтения кода, поэтому данные этих исследований здесь не применимы. А что касается использования исторических причин, которые больше не применяются в качестве обоснования, мы также использовали последние 8.3 имен файлов.
— Конрад Рудольф

28

Обратите внимание на то, что написано в верхней части страницы:

bashate: эквивалент pep8 для скриптов bash

PEP8 - это руководство по стилю для кода Python. В то время как Python люди часто кажется, берут свои проблемы стиля очень серьезно [править] , это как раз то, руководство. Мы могли бы придумать плюсы как для размещения doстроки в одной строке for, так и для собственной линии.

Это та же дискуссия , где ставить {в коде C при запуске ifили whileблок (или такой).


Несколько строк ниже в документации, есть еще одно интересное правило:

E020: объявление функции не в формате ^function name {$

Я предполагаю, что суть в том, что автор этого руководства по стилю считает, что использование functionключевого слова необходимо, чтобы читатель распознал объявление функции. Тем не менее, function fooэто нестандартный способ определения функции: стандартный способ foo(). Единственное различие между ними (в Bash) состоит в том, что другое сложнее портировать на стандартную оболочку, как /bin/shв Debian или Ubuntu.

Итак, я бы предложил взять все эти руководства по стилю с небольшим количеством соли или три, и решить для себя, какой стиль лучше. Хорошая проверка стиля позволяет отключить некоторые проверки (bashate должен bashate -i E010,E011игнорировать эти две проверки.) Отличная проверка стиля позволит вам изменить тесты, например, для проверки противоположности E020, здесь.


12

TL; DR: Вам не нужно. Это просто мнение какого-то чувака.

Как и многие другие, я писал forподобные циклы десятилетиями:

for F in arg1 arg2 arg*
do
    somecommand "$F"
done

Этот макет подчеркивает тот факт, что do ... doneтело цикла окружено, как фигурные скобки в C-подобных языках, и позволяет символам новой строки разделять компоненты конструкции цикла.

Конечно, существуют религиозные войны о том, где размещать фигурные скобки, так что вы могли бы сказать, что жюри все еще отсутствует в этом. ИМХО, это ясно, как это было разработано для работы; Борн увлекался подобранными разделителями, ср. if ... fi, case ... esacИ потребность в точку с запятой в короткой версии показывает , что вы делаете это меньше , чем первоначально разработан. Ничего плохого в этом нет; технологические достижения и многие вещи, которые когда-то казались хорошей идеей, теперь не одобряются goto. Но пока все сообщество сценариев оболочки не примет предпочтения bashateавторов, вам не нужно ничего делать.


3
То, fiчто соответствует ifи esacт. Д., Взято из Алгола 68. Единственная причина, по которой forцикл doне заканчивается od, od- это имя существующей стандартной утилиты. См en.wikipedia.org/wiki/ALGOL_68C#Algol_68C_and_Unix
— Kusalananda

1
Верно, блоки с разделителями по ключевым словам также использовались в других языках семейства Алгол, включая Паскаль (который использует begin ... endи т. Д.).
— Алексис

2
Разве не слышал рассказ о том od, что это смешно ... (Хотя, почему бы тогда не закончить цикл " rof?")
— Алексис

2
@alexis Ну, как сказал Кусалананда, это исходит из Алгола 68, это ключевой момент. Стивен Борн, создатель оригинальной оболочки Bourne, находился под сильным влиянием этого языка, и именно поэтому он придерживался этого синтаксиса. Даже когда он писал на C. Смотрите исходный код оболочки Bourne : minnie.tuhs.org//cgi-bin/utree.pl?file=V7/usr/src/cmd/sh/mac.h Да, и путь, BEGINи ENDтам тоже определены.
— Сергей Колодяжный

1
Кстати, весь этот стиль форматирования также происходит от Algol 68. Его FORи DOбудет также по отдельным линиям, по соглашению, за исключением , когда весь цикл будет легко помещается на одной строке.
— reinierpost

3

Я удивлен, что никто еще не упомянул этот допустимый и переносимый синтаксис:

set alfa bravo charlie
for q do
  echo "$q"
done

Обратите внимание, что forи doнаходятся на одной строке, без точки с запятой. Результат:

alfa
bravo
charlie

Я одобряю этот ответ для включения упоминания об этом непонятном (но в некоторых случаях критическом для чистого и переносимого кода оболочки), однако стоит явно объяснить людям, что это сглаживает позиционные параметры, а также я вынужден упомянуть, что единственная «по-настоящему переносимая (tm)» форма - это та, где for qи doнаходятся в отдельных строках (форма в этом примере не поддерживалась пару десятилетий назад в исходной оболочке Almquish ( ash): in-ulm.de/~mascheck/various/ bourne_args / # endnote )
— mtraceur

Хотя пример в этом ответе работает для меня, применение его к примеру в вопросе OP не работает.
— Scribblemacher

3

Несколько хороших ответов здесь. Всегда берите гидов по стилю с долей соли, и ИМХО, и опыт, будьте очень осторожны в отношении любого сообщества, которое изобилует чрезмерной догмой, когда дело касается стиля. Похоже, они верят, что когда они НАКОНЕЦ получат последнюю точку, которую я поставил, и эту последнюю букву Т, то программное обеспечение будет работать. Иногда для устранения ошибок требуется более чем идеальный стиль ...

Когда я начал изучать оболочку, большинство сценариев и текстов использовали встроенный формат точки с запятой

for i in "$@"; do
    stuff
done

но поскольку я был неопытным, мне было немного трудно определить; и делать - оба необходимы для подтверждения синтаксической правильности. Поэтому я предпочел сделать на следующей строке все сам по себе. Я больше не делаю это (каламбур)

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

while prep1; prep2; condition; do
    stuff
done

но когда команды подготовки немного громоздки и / или условие сложное, его лучше отформатировать как

while
    prep1
    prep2
    condition
do
    stuff
done

и затем добавление do как "; do" является явно ошибочным.

Вы можете даже стать более интенсивным, чем это:

while
    if con1; then
      cond2
    elif cond3; then
      cond4
    elif cond5; then
      cond6
    else
      cond7
    fi
do
    stuff
done

потому что каждое утверждение является выражением. Обратите внимание, как оба стиля используются оппортунистически. Держите это в чистоте, и это вполне читабельно. Уплотните или перекосите его во имя стиля или «экономии места», и это станет ужасным беспорядком.

Так! Учитывая довольно барочные стили сценариев оболочки в целом, все, что направлено на повышение ясности и легкий визуальный доступ к значимым символам, всегда хорошо.

Форма, где «do» написана в строке с командой, приятна, когда у вас есть небольшая команда - я не нахожу «do» визуально скрытым, и внутренняя команда действительно не скрыта:

for i in whatever
  do stuff
done

Я считаю, что на это довольно приятно смотреть, и у него есть аналоги с while, if и case:

while condition
  do stuff
end

if condition
  then stuff1
  else stuff2
fi

case $blah in
  a) stuff1;;
  b) stuff2;;
  c) stuff3;;
  *) stuffInfinity;;
esac

Ясность и общая аккуратность - это все, что просит от вас Кодд *.

* Эдгар Ф. Кодд, отец теории реляционных баз данных.


1
Никогда не видел whileс ifусловием раньше. Круто!
— Джо
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.