Mengapa saya harus menempatkan "lakukan" di baris yang sama dengan "untuk"?

28

1. Ringkasan

Saya tidak mengerti, mengapa saya perlu aturan bashate E010 .


2. Detail

Saya menggunakan bashate untuk .shfile linting . Aturan E010:

jangan di baris yang sama seperti untuk

for bashate:

  • Benar:

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

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

Apakah ada argumen yang valid, mengapa saya perlu fordan dodi baris yang sama?


3. Tidak berguna

Saya tidak dapat menemukan jawaban untuk pertanyaan saya di:

  1. Google
  2. Artikel tentang praktik pengkodean terbaik ( contoh )
  3. dokumentasi bashate . Saya hanya menemukan:

    Seperangkat aturan yang membantu menjaga hal-hal konsisten di blok kontrol. Ini diabaikan pada garis panjang yang memiliki kelanjutan, karena membuka gulungan yang agak "menarik"

Саша Черных
sumber
3
Lekukannya dojelas agak tidak biasa, tetapi for ... \ndo\n<indent>body...sangat umum dan saya bahkan memperkirakan lebih dari itu for ... ; do. Apakah itu juga mengeluh tentang itu?
Michael Homer
20
bashateadalah pemeriksa gaya . Gaya secara inheren bersifat subyektif. Jangan menggunakannya jika Anda tidak menyukai gaya artibrary yang diterapkannya. Anda sebaiknya mempertimbangkan pemeriksa sintaks / bug seperti shellcheck .
meuh
@meuh, terima kasih, saya sudah menggunakan ShellCheck. pertanyaan saya: E010- hanya gaya aturan atau dalam beberapa kasus saya perlu untuk dan lakukan di baris yang sama tidak hanya oleh alasan gaya.
Саша Черных
10
Tidak pernah ada kewajiban sintaksis untuk memiliki untuk dan lakukan pada baris yang sama di shell.
meuh
1
@ Саша Черных Ini bukan lekukan dengan sendirinya yang tidak biasa, itu lekukan dari do. Ini seperti indentasi penjepit pembukaan ifdan menambahkan kode pada baris yang sama dalam bahasa seperti C. Contoh lain, jika python mengijinkannya, akan menempatkan :sebuah ifmenjorok pada baris berikutnya dan menambahkan kode pada baris yang sama. Ini akan membuatnya berbeda dengan garis tambahan di dalam tubuh.
JoL

Jawaban:

60

Secara sintaksis, dua cuplikan kode berikut ini benar dan setara:

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

Yang terakhir mungkin bisa dikatakan lebih sulit untuk dibaca karena dosedikit mengaburkan perintah dalam tubuh loop. Jika loop berisi banyak perintah dan perintah berikutnya ada di baris baru, kebingungan akan lebih disorot:

for f in *
    do cmd1
    cmd2
done

... tetapi untuk menandainya sebagai "kesalahan" adalah pendapat pribadi seseorang IMHO daripada kebenaran obyektif.

Secara umum, hampir semua ;dapat digantikan oleh baris baru. Keduanya ;dan baris baru adalah terminator perintah. doadalah kata kunci yang berarti "di sini mengikuti apa yang perlu dilakukan (dalam forloop ini )".

for f in *; do ...; done

sama dengan

for f in *
do
   ...
done

dan sebagai

for f in *; do
   ...
done

Alasan untuk menggunakan satu sama lain adalah keterbacaan dan konvensi gaya lokal / pribadi.


Opini pribadi:

Dalam header loop yang sangat panjang , saya pikir mungkin masuk akal untuk meletakkan dobaris baru, seperti pada

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

atau

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

Hal yang sama berlaku untuk thendalam ifpernyataan.

Tetapi sekali lagi, ini tergantung pada preferensi gaya pribadi seseorang, atau untuk gaya pengkodean apa pun yang digunakan tim / proyek seseorang.

Kusalananda
sumber
Anda mengatakan bahwa "Dalam header loop yang sangat panjang, mungkin masuk akal untuk dilakukan di baris baru". Bisakah Anda memberikan alasan untuk itu? Mengingat bahwa tajuk harus diikuti do, saya tidak melihat alasan mengapa meletakkannya di baris berikutnya akan membantu keterbacaan.
Konrad Rudolph
3
@KonradRudolph Terminal saya memiliki lebar 80 karakter. Jika daftar membungkus, saya akan membuatnya menjadi satu set garis berkelanjutan (seperti dalam contoh terakhir saya), jika hampir membungkus, saya akan meletakkan do(atau then) pada baris sendiri (seperti pada contoh kedua ke terakhir). Ini semua harus dengan preferensi pribadi. Saya tidak suka garis yang terlalu panjang, sebagian karena terminal saya "hanya" 80 karakter lebar, dan sebagian karena saya pikir itu terlihat berantakan. Saya juga merasa sulit untuk menguraikan garis yang sangat panjang untuk kesalahan.
Kusalananda
1
Tampaknya tidak perlu untuk terus menunjukkan bahwa ini adalah opini. bashate adalah panduan gaya, jadi itu berdasarkan opini.
Barmar
4
@Barmar, harap dicatat bahwa pertanyaan di sini menggunakan ungkapan seperti "perlu" dan "memerintah", dan panggilan readme bashate yang memiliki dopada baris terpisah merupakan "kesalahan". Mereka agak frase yang ketat, sehingga tidak tampak layak untuk menunjukkan bahwa, cukup sebaliknya, yang disebut "aturan" sebenarnya hanya opini subjektif.
ilkkachu
2
@traceur Benar, saya tidak mempertanyakan preferensi pribadi. Namun ketahuilah bahwa batas kolom keterbacaan yang Anda kutip tidak berlaku untuk kode. Itu hanya berlaku untuk prosa. Gerakan mata pada dasarnya berbeda untuk membaca kode, jadi bukti dari studi tersebut tidak berlaku di sini. Dan untuk menggunakan alasan historis yang tidak lagi berlaku sebagai alasan, kami juga telah menggunakan 8,3 nama file.
Konrad Rudolph
28

Perhatikan apa yang tertulis di bagian atas halaman:

bashate: Setara pep8 untuk skrip bash

PEP8 adalah Panduan Gaya untuk Kode Python. Sementara Python orang sering tampaknya mengambil isu-isu gaya mereka sangat serius [rujukan?] , Hanya saja, pemandu. Kita bisa membuat sisi negatif untuk menempatkan keduanya dodi baris yang sama dengan for, dan untuk menempatkannya pada barisnya sendiri.

Ini adalah diskusi yang sama dengan tempat memasukkan {kode C saat memulai ifatau whilememblokir (atau semacamnya).


Beberapa baris di bawah ini dalam dokumentasi, ada aturan lain yang menarik:

E020: Deklarasi fungsi tidak dalam format ^function name {$

Saya berasumsi intinya di sini adalah bahwa penulis panduan gaya berpikir bahwa menggunakan functionkata kunci diperlukan bagi pembaca untuk mengenali deklarasi fungsi. Namun, function foocara non-standar untuk mendefinisikan suatu fungsi: cara standar adalah foo(). Satu-satunya perbedaan antara keduanya (dalam Bash) adalah bahwa yang lain lebih sulit untuk port ke shell standar, seperti /bin/shdi Debian atau Ubuntu.

Jadi, saya akan menyarankan mengambil setiap dan semua panduan gaya tersebut dengan sebutir garam atau tiga, dan memutuskan untuk diri sendiri apa gaya terbaik. Pemeriksa gaya yang baik memungkinkan penonaktifan beberapa cek (bashate harus bashate -i E010,E011mengabaikan kedua pemeriksaan itu.) Pemeriksa gaya yang hebat akan memungkinkan Anda untuk memodifikasi tes, misalnya untuk memeriksa kebalikan dari E020, di sini.

ilkkachu
sumber
12

TL; DR: Anda tidak perlu. Itu hanya pendapat beberapa pria.

Seperti banyak orang lain, saya telah menulis forloop seperti ini selama beberapa dekade:

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

Layout ini menyoroti fakta yang do ... donemengelilingi tubuh loop, seperti kurung kurawal dalam bahasa mirip-C, dan memungkinkan baris baru untuk memisahkan komponen konstruksi loop.

Tentu saja ada perang agama tentang di mana menempatkan kurung kurawal juga, jadi Anda bisa mengatakan juri masih keluar tentang yang satu ini. IMHO, ini jelas bagaimana ini dirancang untuk bekerja; Bourne menyukai pembatas yang cocok, lih. if ... fi,, case ... esacdan perlunya titik koma di versi yang lebih pendek mengungkapkan bahwa Anda membuatnya lebih pendek dari yang dirancang semula. Tidak ada yang salah dengan itu; kemajuan teknologi dan banyak hal yang dulu tampak seperti ide bagus sekarang disukai, seperti goto. Tetapi sampai seluruh komunitas skrip shell mengadopsi preferensi bashatepenulis, Anda tidak perlu melakukan apa pun.

alexis
sumber
3
Yang fisesuai dengan if, dan esaclain - lain berasal dari Algol 68. Satu-satunya alasan forloop dotidak diakhiri odadalah karena oditulah nama utilitas standar yang ada. Lihat en.wikipedia.org/wiki/ALGOL_68C#Algol_68C_and_Unix
Kusalananda
1
Blok yang tepat dan dibatasi kata kunci juga digunakan dalam bahasa lain dari keluarga Algol, termasuk Pascal (yang menggunakan begin ... enddll.).
Alex
2
Belum pernah mendengar cerita tentang itu od, itu lucu ... (Meskipun, mengapa tidak hanya berakhir dengan rof, ya?)
alexis
2
@alexis Yah, seperti kata Kusalananda, itu berasal dari Algol 68, itulah poin kuncinya. Stephen Bourne, pencipta cangkang Bourne asli, sangat dipengaruhi oleh bahasa itu, dan itulah sebabnya dia berpegang pada sintaksis itu. Bahkan ketika dia menulis dalam C. Lihat kode sumber untuk bourne shell: minnie.tuhs.org//cgi-bin/utree.pl?file=V7/usr/src/cmd/sh/mac.h Oh, dan oleh cara, BEGINdan ENDdidefinisikan di sana juga.
Sergiy Kolodyazhnyy
1
Gaya pemformatan keseluruhan ini juga berasal dari Algol 68, omong-omong. Ini FORdan DOjuga akan berada di jalur yang terpisah, dengan konvensi, kecuali ketika seluruh loop dengan mudah akan muat pada satu baris.
reinierpost
3

Saya terkejut belum ada yang menyebutkan sintaks yang valid dan portabel ini:

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

Perhatikan baik-baik itu fordan doberada di jalur yang sama, tanpa titik koma. Hasil:

alfa
bravo
charlie
Steven Penny
sumber
Saya menyetujui jawaban ini untuk memasukkan penyebutan sintaks yang tidak jelas ini (tetapi penting untuk kode shell yang bersih dan portabel dalam beberapa kasus), namun ada baiknya menjelaskan secara eksplisit kepada orang-orang bahwa ini mengacaukan parameter posisi, dan juga, saya merasa terdorong untuk menyebutkan bahwa satu-satunya bentuk "benar-benar portabel (tm)" adalah di mana for qdan doberada pada baris yang terpisah (formulir dalam contoh ini tidak didukung beberapa dekade yang lalu pada shell Almquish asli ( ash): in-ulm.de/ ~mascheck / various/ bourne_args / # endnote )
mtraceur
Sementara contoh dalam jawaban ini berfungsi untuk saya, menerapkannya pada contoh dalam pertanyaan OP tidak berfungsi.
Scribblemacher
3

Beberapa jawaban bagus di sini. Selalu ambil panduan gaya dengan sebutir garam, dan IMHO dan pengalaman, menjadi sangat-sedikit-untuk-sedang khawatir tentang setiap komunitas yang penuh dengan dogma berlebihan ketika datang ke gaya. Ini hampir seperti mereka percaya bahwa ketika mereka AKHIRNYA mendapatkan yang terakhir saya putus-putus, dan yang terakhir terlewati, maka perangkat lunak akan bekerja. Terkadang dibutuhkan lebih dari gaya yang sempurna untuk menghapus bug ...

Ketika saya mulai belajar shell, sebagian besar skrip dan tute di luar sana menggunakan format titik koma in-line

for i in "$@"; do
    stuff
done

tetapi karena saya tidak berpengalaman, saya agak kesulitan menemukan; dan do - keduanya penting untuk mengkonfirmasi kebenaran sintaksis. Jadi saya lebih suka lakukan pada baris berikutnya dengan sendirinya. Saya tidak lagi melakukan itu (pun intended)

Selanjutnya, perintah 'while' adalah kandidat yang sangat baik untuk trik kecil yang menyenangkan:

while prep1; prep2; condition; do
    stuff
done

tetapi ketika perintah prep agak besar, dan / atau kondisinya kompleks, lebih baik diformat sebagai

while
    prep1
    prep2
    condition
do
    stuff
done

dan kemudian menambahkan do sebagai "; do" positif.

Anda bahkan bisa lebih intens dari itu:

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

karena setiap pernyataan adalah ekspresi. Perhatikan bagaimana kedua gaya digunakan secara oportunistik. Tetap bersih dan cukup mudah dibaca. Memadatkan atau membelokkannya atas nama gaya atau "menghemat ruang" dan itu menjadi berantakan.

Begitu! Mengingat stylings skrip shell yang agak barok pada umumnya, segala sesuatu yang bertujuan meningkatkan kejelasan dan akses visual yang mudah ke simbol-simbol penting selalu merupakan hal yang baik.

Bentuk di mana 'do' ditulis sesuai dengan perintah itu manis ketika Anda memiliki sedikit perintah - Saya tidak menemukan 'do' disembunyikan secara visual, juga tidak ada perintah batin yang benar-benar dikaburkan:

for i in whatever
  do stuff
done

Saya menemukan itu cukup menyenangkan untuk dilihat, dan memiliki analog dengan while, if dan case:

while condition
  do stuff
end

if condition
  then stuff1
  else stuff2
fi

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

Kejelasan dan kerapian umum adalah semua yang diminta Codd dari Anda.

* Edgar F. Codd, bapak teori database relasional.


sumber
1
Belum pernah melihat whiledengan ifkondisi sebelumnya. Keren!
Joe