Предпочтительный синтаксис для двухстрочного длинного канала

Предпочтительный синтаксис для двухстрочного длинного канала

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

Эта длинная командная строка:

ruby -run -e httpd -- -p 5000 . 2>&1 | tee >(grep -Fq 'WEBrick::HTTPServer#start' && open localhost:5000) 

Можно разделить следующим образом:

ruby -run -e httpd -- -p 5000 . 2>&1 \
   | tee >(grep -Fq 'WEBrick::HTTPServer#start' && open localhost:5000) 

Или:

ruby -run -e httpd -- -p 5000 . 2>&1 |
    tee >(grep -Fq 'WEBrick::HTTPServer#start' && open localhost:5000) 

Суммируя:

command1 \
    | command2

Или:

command1 |
    command2

Я понимаю, что это может быть вопросом стиля (мнения), но: есть ли предпочтительный способ, и если да, то почему?

решение1

Спросите себя, к чему это приведет?

command1 \ 
   | command2

Не вижу разницы. Я тоже не вижу, но оболочка видит. Посмотрите внимательно, после \. Это не дает экранировать новую строку.

Поэтому используйте другую форму, так как она безопаснее. Здесь показано с той же ошибкой (в данном случае пробел после |). Но это не вызывает ошибку.

command1 | 
    command2

решение2

Я не соглашусь с большинством людей здесь; я всегда предпочитаю оборачиватьдооператор соединения, такой как труба:

command1 \
| command 2

(Вам не нужно делать отступ во второй строке; вертикальная черта сама по себе очень очевидно связывает ее с первой.)

На это есть несколько причин:

  • Это легче увидеть.соединитель; он не теряется среди деталей строки. (Это особенно важно, если строка длинная, и соединитель мог прокрутиться или потеряться среди переносов строк.) Когда вы быстро просматриваете код, вы смотрите вниз на левую сторону, потому что именно там находится общая структура: в отступах, фигурных скобках или в том, что используется в конкретном языке. Каналы и другие соединительные элементы важны для структуры, поэтому они тоже должны быть слева.

  • Он выстраивается в линиюесли вы охватываете 3 или более линий. Опять же, это позволяет легко охватить структуру конвейера с первого взгляда.

  • Это ближе к нашему образу мышления.. (Это самый тонкий и спорный момент…) Если вы медленно зачитываете список, чтобы кто-то мог его записать, вы бы сказали: «[Пункт 1]…(Пауза)… и [Пункт 2]…(Пауза)… и [Элемент 3]»; было бы неестественно сказать «[Элемент 1] и…(Пауза)… [Пункт 2] и…(Пауза)… [Элемент 3]». Это потому, что мы думаем, что соединитель присоединяется к следующему элементу больше, чем к предыдущему. (Вы можете думать о знаке минус в арифметике в похожих терминах; он работает как сложение, но более тесно соединяется со следующим числом, отрицая его.) Код легче понимать, когда он отражает наши мысли.

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

решение3

Ну, просто чтобы не создать впечатление, что это никому не нравится:

command1 \
   | command2

Я скажу, что да.

Я считаю, что проблема с конечными пробелами, вызванная ctrl-alt-delor, не является проблемой. Редакторы могут предупреждать об этом; git предупреждает об этом. В довершение всего, оболочка выдаст синтаксическую ошибку на | command2, предоставив пользователю файл и номер строки с ошибкой, и прекратит интерпретировать остальную часть файла:

$ cat f.sh
#!/bin/bash

echo foo \ 
| command2

echo bar
$ ./f.sh
foo  
./f.sh: line 4: syntax error near unexpected token `|'
./f.sh: line 4: `| command2'

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

ffmpeg \
  -f x11grab \
  -video_size "$size" \
  -framerate "${framerate:-10}" \
  -i "${DISPLAY}${offset}" \
  -c:v ffvhuff \
  -f matroska \
  -

Должны ли мы избегать такого использования, потому что мы не можем себе позволить не ставить пробел после символа перехода?

Мои предпочтения — это исключительно вопрос читабельности, и они довольно субъективны. Вот реальный пример из моей истории оболочки (с заменой деталей на foobar):

org-table-to-csv foobar.org \
| cq +H -q "
  select foo
    from t
    where bar = 'baz'
      and foo != ''" \
| sed -r 's/^|$/'\''/g' \
| sed -r ':b;$!{N;bb};s/\n/, /g'

По сравнению с:

org-table-to-csv foobar.org |
  cq +H -q "
    select foo
      from t
      where bar = 'baz'
        and foo != ''" |
  sed -r 's/^|$/'\''/g' |
  sed -r ':b;$!{N;bb};s/\n/, /g'

Вот еще:

sed 's/ .*//' <<< "$blame_out"
| sort \
| uniq \
| tee >(sed "s/^/from pipe before grep filtering: /" > /dev/tty) \
| grep -vF "$(git show -s --format=%h "$from_commit")" \
| tee >(sed "s/^/from pipe before git show: /" > /dev/tty) \
| xargs git show -s --format='%cI %h' \
| tee >(sed "s/^/from pipe after git show: /" > /dev/tty) \
| sort -k1 \
| tail -1 \
| cut -d' ' -f2

По сравнению с:

sed 's/ .*//' <<< "$blame_out"
  sort |
  uniq |
  tee >(sed "s/^/from pipe before grep filtering: /" > /dev/tty) |
  grep -vF "$(git show -s --format=%h "$from_commit")" |
  tee >(sed "s/^/from pipe before git show: /" > /dev/tty) |
  xargs git show -s --format='%cI %h' |
  tee >(sed "s/^/from pipe after git show: /" > /dev/tty) |
  sort -k1 |
  tail -1 |
  cut -d' ' -f2

решение4

Я думал, что ответ на этот вопрос будет простым, но вижу, что @JoL и @gidds со мной не согласны.

My brain prefers reading a line and not having to scan the next line \
:

  foo bar baz ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... \

In the above I will have to see \
, what is on line 2 \
, before I can tell \
, what the command does \
. Maybe the command is complete \
? Or maybe the command continues \
  on the next line \
?

To me it is much easier to read,
if \ is only used,
when a command cannot fit on a line.

Читая свой код, я также вижу проблему в комментариях:

foo ... ... ... ... ... ... ... ... |
    # Now this does bar
    bar ... ... ... ... ... ... ... ... ||
    # And if that fails: fubar
    fubar

Я не уверен, как вы вообще будете делать комментарии в середине конвейера, если вы используете \+ newline перед |или ||или &&. Если это невозможно, я думаю, что это самая важная проблема. Код не может быть поддержан без комментариев, и комментарии обычно должны быть как можно ближе к коду, чтобы поощрять обновление документации при изменении кода.

Emacs автоматически делает отступы, так что они даже не являются дополнительной нагрузкой:

# This is indented automatically in emacs
ruby -run -e httpd -- -p 5000 . 2>&1 |
    # Send the output to the screen and to grep
    tee >(grep -Fq 'WEBrick::HTTPServer#start' &&
              # If grep matches, open localhost:5000
              open localhost:5000) 
# Here is where emacs indents the next command to

Связанный контент