2 行の長いパイプの推奨構文

2 行の長いパイプの推奨構文

長いパイプを書くときは、通常、2 行に分ける方が明確になります。

この長いコマンドライン:

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

(2 行目をインデントする必要はありません。パイプ自体が 1 行目に非常に明確にリンクしています。)

これにはいくつかの理由があります:

  • 見やすくなりましたジョイナーは行の細部に埋もれません。(行が長く、ジョイナーがスクロールされて見えなくなったり、行の折り返しに埋もれたりする可能性がある場合は、特に重要です。) コードを素早くスキャンするときは、左側を見ます。なぜなら、そこにインデント、中括弧、または特定の言語で使用されるものなど、全体的な構造があるからです。パイプやその他のジョイナーは構造にとって重要なので、それらも左側に配置する必要があります。

  • 並んでいる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

またはまたは\の前に + 改行を使用する場合、パイプラインの途中でコメントをどのように行うのかまったくわかりません。それが不可能な場合は、これが最も重要な問題だと思います。コードはコメントなしでは保守できません。また、コードを変更したときにドキュメントを更新できるように、コメントは通常、コードにできるだけ近づける必要があります。|||&&

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

関連情報