bash lệnh đa dòng với các bình luận sau ký tự tiếp tục


29

Xem xét

echo \ # this is a comment
foo

Điều này mang lại:

$ sh foo.sh
 # this is a comment
foo.sh: line 2: foo: command not found

Sau một số tìm kiếm trên web, tôi đã tìm thấy một giải pháp của DigitalRoss trên trang web chị em Stack Overflow. Vì vậy, một người có thể làm

echo `: this is a comment` \
foo

Hay cách khác

echo $(: this is a comment) \
foo

Tuy nhiên, DigitalRoss không giải thích lý do tại sao các giải pháp này hoạt động. Tôi đánh giá cao một lời giải thích. Ông trả lời với một bình luận:

Đã từng có một gotolệnh shell được phân nhánh đến các nhãn được chỉ định như :ở đây. Đã gotobiến mất nhưng bạn vẫn có thể sử dụng : whatevercú pháp ... :là một loại nhận xét được phân tích cú pháp ngay bây giờ.

Nhưng tôi muốn biết thêm chi tiết và bối cảnh, bao gồm cả một cuộc thảo luận về tính di động.

Tất nhiên, nếu bất cứ ai có giải pháp khác, điều đó cũng sẽ tốt.

Xem thêm câu hỏi trước Làm thế nào để bình luận các lệnh nhiều dòng trong shell script? .


Mang tin nhắn về nhà từ các cuộc thảo luận dưới đây. Đây `: this is a comment`chỉ là một sự thay thế lệnh. Đầu ra của : this is a commentkhông có gì, và được đặt vào vị trí của `: this is a comment`.

Một lựa chọn tốt hơn là như sau:

echo `# this is a comment` \
foo

Câu trả lời:


25

Nhận xét kết thúc ở dòng mới đầu tiên (xem quy tắc nhận dạng mã thông báo shell 10 ), mà không cho phép các dòng tiếp tục , vì vậy mã này có footrong một dòng lệnh riêng biệt:

echo # this is a comment \
foo

Đối với đề xuất đầu tiên của bạn, dấu gạch chéo ngược không theo dòng mới, bạn chỉ trích dẫn khoảng trắng: nó tương đương với

echo ' # this is a comment'
foo

$(: this is a comment)thay thế đầu ra của lệnh : this is a comment. Nếu đầu ra của lệnh đó trống, đây thực sự là một cách rất khó hiểu để chèn một bình luận ở giữa một dòng.

Không có phép thuật nào xảy ra: :là một lệnh thông thường, tiện ích dấu hai chấm , không có gì. Tiện ích dấu hai chấm chủ yếu hữu ích khi cú pháp shell yêu cầu một lệnh nhưng bạn không có gì để làm.

# Sample code to compress files that don't look compressed
case "$1" in
  *.gz|*.tgz|*.bz2|*.zip|*.jar|*.od?) :;; # the file is already compressed
  *) bzip2 -9 "$1";;
esac

Một trường hợp sử dụng khác là một thành ngữ để đặt một biến nếu nó chưa được đặt.

: "${foo:=default value}"

Nhận xét về goto là một lịch sử. Tiện ích đại tràng bắt nguồn từ ngay cả trước khi vỏ Bourne , tất cả các cách đến vỏ Thompson , có hướng dẫn goto . Dấu hai chấm có nghĩa là một nhãn hiệu; dấu hai chấm là một cú pháp khá phổ biến cho nhãn goto (nó vẫn hiện diện trong sed ).


Ok, tôi hiểu rồi. Có cách nào tốt hơn để chèn bình luận trong bối cảnh này mà bạn biết không?
Faheem Mitha

3
@FaheemMitha Theo khuyến nghị trong chuỗi bạn trích dẫn: chia lệnh của bạn thành các phần có thể quản lý và nhận xét từng đoạn. Nếu lệnh của bạn phức tạp đến mức cần một bình luận ở giữa, đã đến lúc đơn giản hóa nó!
Gilles 'SO- ngừng trở nên xấu xa'

1
Chà, lệnh trong câu hỏi có rất nhiều đối số ... Đó là chuyển đổi một loạt các tệp video thành một tệp. Tôi không thấy một cách trực tiếp để đơn giản hóa nó. Có thể tạo một danh sách một số loại, và vượt qua nó như là một đối số? Tôi đoán đó có thể là một câu hỏi khác.
Faheem Mitha

@FaheemMitha Ví dụ : make_FIND, một kịch bản quickie xây dựng một danh sách dài các đối số find. Ở đây, động lực để xây dựng nó chunk bởi chunk là mỗi chunk đến từ cơ thể của một vòng lặp, nhưng cùng một phong cách cho phép nhận xét về từng chunk.
Gilles 'SO- ngừng trở nên xấu xa'

1
Cảm ơn ví dụ. Ví dụ của tôi về cơ bản chỉ là một danh sách dài các tên được đưa ra làm đối số cho một lệnh. Tôi muốn bình luận gắn liền với mỗi tên, bởi vì đó là cách dễ nhất để tôi giữ bối cảnh. Tôi không thấy bất kỳ cách rõ ràng nào để phá vỡ lệnh thành từng mảnh và nếu tôi làm vậy, nó có thể khiến nó dài hơn nữa và nó đã đủ dài.
Faheem Mitha

6

Bạn có thể đạt được điều này bằng cách sử dụng mảng Bash, vd

#!/bin/bash
CMD=(
  echo  # this is a comment
  foo
  )

"${CMD[@]}"

Điều này xác định một mảng $CMD, và sau đó mở rộng nó. Sau khi mở rộng dòng kết quả được ước tính, vì vậy trong trường hợp echo foonày được thực thi.

Văn bản giữa ()định nghĩa mảng và tuân theo cú pháp bash thông thường, vì vậy mọi thứ trên một dòng sau #sẽ bị bỏ qua.

Lưu ý về việc giữ nguyên khoảng trắng được trích dẫn

${CMD[@]}mở rộng thành một chuỗi duy nhất là sự kết hợp của tất cả các phần tử, cách nhau bởi một khoảng trắng. Sau khi được mở rộng, Bash sẽ phân tích chuỗi thành các mã thông báo theo cách thông thường (cf $ IFS ), thường không phải là thứ chúng ta muốn.

Ngược lại, nếu việc mở rộng được gói trong dấu ngoặc kép, nghĩa là "${CMD[@]}", mỗi phần tử trong mảng được bảo toàn. Hãy xem xét sự khác biệt giữa hello world second item"hello world" "second item".

Ví dụ minh họa:

# LIST=("hello world" "second item")

# for ITEM in ${LIST[@]}; do echo $ITEM; done
hello
world
second
item

# for ITEM in "${LIST[@]}"; do echo $ITEM; done
hello world
second item

Cảm ơn bạn đã trả lời, @RobM. Vì vậy, đề xuất của bạn là bao gồm các ý kiến ​​/ thông tin meta về các mục trong danh sách trong chính mảng bash? Câu hỏi này có lẽ sẽ hữu ích hơn nếu tôi đưa vào một ví dụ về loại lệnh tôi đang cố sử dụng. Tôi không biết tại sao tôi lại không.
Faheem Mitha

Bah, hóa ra tôi đã không đọc kỹ câu hỏi của bạn. Nghĩ rằng bạn đã hỏi câu hỏi mà bạn liên kết đến. Rất tiếc. :)
RobM

${CMD[@]}không mở rộng đến một đơn chuỗi. - Nó mở rộng ra nhiều chuỗi: Không chỉ phân chia cho từng phần tử của mảng, mà còn trên khoảng trắng trong mỗi phần tử. (Tức là: hoàn toàn vô dụng)
Robert Siemer

4

Đừng làm thế $(: comment). Đó không phải là một nhận xét - đó là một nhánh con - một quá trình vỏ hoàn toàn mới khác cho hầu hết các vỏ. Mục tiêu của bạn là làm ít hơn với đầu vào của bạn, không nhiều hơn, đó là những gì sẽ làm - ngay cả khi nó là vô nghĩa.

Thay vào đó, bạn có thể làm ...

printf '<%s>\n' some args here ${-##*"${--

                my long comment block

                }"}  and "more ${-##*"${--

                and another one in the
                middle of the quoted string
                there shouldn\'t b\e any special &
                (character) `echo issues here i hope >&2`
                basically anything that isn\'t a close \}
                $(echo the shell is looking for one >&2)
                }$(echo "}'"\" need backslash escaping >&2
                                )${-##*${--

                nesting is cool though

             }}"}here too"

}'" need backslash escaping
<some>
<args>
<here>
<and>
<more here too>

Về cơ bản những gì đang xảy ra có vỏ đang thay thế. Nó thay thế giá trị của tham số shell đặc biệt $-hai lần mỗi lần. Dù sao đó cũng là một chuỗi ngắn, nhưng nó luôn được đặt - và do đó, sự thay thế bên trong - được hiểu là một mẫu để tách khỏi bên ngoài - không mở rộng ra nội dung giữa các dấu ngoặc đơn khi tôi sử dụng -biểu mẫu mở rộng.

Đây:

bash -x <<""
printf %s\\n '${-##*"'${-- a set param doesn\'t expand to this optional text }'"}'

+ printf '%s\n' '${-##*"hxB"}'
${-##*"hxB"}

Xem? Vì vậy, nó chỉ mở rộng hai lần. Ngay khi shell tìm thấy tham số được đặt, mọi thứ trong trường mở rộng tùy chọn sẽ bị loại bỏ, khá nhiều và nó mở rộng ra toàn bộ giá trị của nó được loại bỏ khỏi chính nó và không có gì cả. Trong hầu hết các shell bạn thậm chí không cần thoát dấu ngoặc kép, nhưng bashyêu cầu nó.

Vẫn còn tốt hơn là:

COMMENT=
echo      ${COMMENT-"
           this will work the same way
           but the stripping isn\'t
           necessary because, while
           the variable is set, it is also
           empty, and so it will expand to
           its value - which is nothing
           "} this you\'ll see

this you'll see
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.