Tại sao trình tự quan trọng trong việc thực hiện các lệnh bash này?


10

Dường như có một số mâu thuẫn mà tôi không thể hiểu được về bash shell.

Nếu tôi thực thi:

ls;date;time

kết quả của ba truy vấn được hiển thị theo trình tự.

Tuy nhiên, vào ngày và vị trí thời gian thay thế, một thông báo lỗi bật lên.

Vì vậy, nếu tôi thực thi:

ls;time;date

thông báo lỗi cho biết : bash: syntax error near unexpected token 'date'.

Ai đó có thể giải thích điều này?


Vấn đề của bạn nói dối về time;datevs date;time. Đây có vẻ là một vấn đề với đường ống trong bashvà char cuối cùng được tạo ra với timeđầu ra. Các kết quả được kiểm tra trong các trình giả lập thiết bị đầu cuối khác nhau là: - [Bash] $ date; time # [OK] $ time; date # [ NotOK ] bash: lỗi cú pháp gần mã thông báo không mong đợi `date '$ time # chỉ lỗi không xuất hiện rằng đó là lỗi kết quả của bất kỳ ngày nào. - [Csh] $ date; time # [OK] $ time; date # [OK] - [Tcsh] $ date; time # [OK] $ time; date # [OK] - [Ksh] $ date; time # [ OK] $ time; ngày # [OK]
Mostafa Shahverdy

Tôi đã cập nhật câu trả lời của mình với một lời giải thích cho thông báo lỗi. Vui lòng kiểm tra xem đây là câu trả lời bạn đang tìm kiếm.
zwets

Câu trả lời:


10

Các timelệnh trong đường ống của bạn không phải là /usr/bin/timenhị phân, nhưng bash timebuilt-in. So sánh man timevới help time. Lỗi bạn thấy là bash không phân tích timeđược đối số. Điều này hoặc phải có mặt hoặc là một dòng mới. Đây là một dòng mới trong ví dụ đầu tiên của bạn nhưng vắng mặt trong lần thứ hai.

Mặt khác, nếu bạn chạy

ls;date;'time'

hoặc là

ls;'time';date

trong đó các trích dẫn xung quanh 'time'thu hồi trạng thái của nó dưới dạng một từ dành riêng, thì bash không có vấn đề gì khi phân tích dòng. Bây giờ nó phân tích ba lệnh trong một danh sách, nó sẽ thực hiện theo trình tự và /usr/bin/timesẽ báo cáo lỗi sử dụng trong cả hai trường hợp.

Phụ lục

Nó đã được quan sát thấy rằng mặc dù time ; datemang lại một lỗi, time ; ; datekhông. Giải thích có khả năng là time ;được giải thích bởi bash tương đương với time <newline>. Biểu thức time ; ; datesau đó được phân tích cú pháp như danh sách time ;date.

Điều này phù hợp với quan sát rằng time ;time ; ;cũng hợp pháp, lần thứ hai được phân tích cú pháp dưới dạng danh sách đơn có chứa time ;dấu chấm phẩy tùy chọn được phép sau danh sách.

Vì vậy, một cách khác để giải thích tại sao time ; datemang lại lỗi bash: syntax error near unexpected token 'date'timetiêu thụ dấu chấm phẩy tách nó ra date. Nó chỉ có thể làm điều đó bởi vì timelà một từ dành riêng bash.


Cảm ơn cho một lời giải thích tốt đẹp! Nhưng một lần nữa, hành vi này trông giống như một lỗi đối với tôi: timeđược cho là cho phép một lệnh NULL và dấu chấm phẩy được cho là để phân định danh sách, vì vậy IMO timelệnh không nên "tiêu thụ" dấu chấm phẩy sau nó. Các lệnh dựng sẵn khác (có thể lấy đối số) không thể hiện loại hành vi này.
sắp xếp

@arrange Sự phức tạp là thời gian không cho phép một lệnh null (điều đó sẽ làm mất đi mọi thứ), nó chỉ cho phép một dòng mới thay cho lệnh. Vì vậy, time;datethực sự là sai về mặt cú pháp trong bất kỳ giải thích. Tuy nhiên time ;time ; ;sau đó cũng sẽ là bất hợp pháp. Nó có thể được tranh luận cho dù timehành vi 's là một lỗi hoặc chỉ đơn thuần là cung cấp tài liệu (nó trong nội bộ phù hợp), nhưng một báo cáo lỗi chắc chắn sẽ được đặt đúng chỗ. Bạn có sẵn sàng nộp nó không?
zwets

Chà, tôi đã xem nguồn (bash4.2: parse.y: dòng 1205-1221) và ở đó nó nói rằng time by itself can time a null commandvà sau đó nó làm như vậy $$ = make_simple_command (x, (COMMAND *)NULL);. Đối với việc gửi một lỗi tôi không chắc chắn 8)
sắp xếp

Cần lưu ý rằng vấn đề này là cụ thể bash. Làm time ; dateviệc trong ksh93mkshkhông có lỗi, mặc dù trong ksh đó có timetừ khóa.
Sergiy Kolodyazhnyy

2

Bash coi tích hợp timenhư một trường hợp đặc biệt, khi phân tích cú pháp dòng lệnh.

Như có thể được đọc trong trang bash, dòng được gõ trước tiên được chia thành một danh sách:

pipeline ; pipeline

nơi một đường ống là:

[time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]

hoặc trong trường hợp của chúng tôi, chỉ cần:

time command

tức là nếu có thời gian thì lệnh cũng phải có mặt.

[Có một trường hợp đặc biệt cho phép timetheo dõi một dòng mới, nhưng điều đó không áp dụng ở đây]

Vì vậy, trong trường hợp của chúng tôi, chúng tôi có:

time;date

được chia thành hai đường ống:

1. time
2. date

và đường ống 1 không được hình thành tốt, vì chúng ta timekhông có lệnh. Do đó có lỗi.

Lưu ý rằng dòng lệnh timekhông hoạt động ở đây:

$ /usr/bin/time;date
Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]

bash phân tích cú pháp này như mong đợi, thành 2 đường ống:

1. /usr/bin/time
2. date

/usr/bin/timesau đó từ chối chạy mà không có đối số. Lưu ý rằng đây là lỗi từ /usr/bin/timekhông phải lỗi từ bash.

Lý do mà back-tick hoạt động là vì back-tick dừng timeđược hiểu là một yếu tố đặc biệt trong đường ống.

tức là với back-tick:

`time`;date

nó được phân tích thành hai đường ống:

1. `time`
2. date

Hãy nhớ rằng một đường ống, trong trường hợp của chúng tôi, là:

[time] command

và vấn đề ban đầu là chúng tôi timekhông có lệnh, điều đó không được phép. Nhưng bây giờ chúng ta chỉ cần có lệnh:

`time`

không có từ trước time, vì dấu tick có nghĩa timeđược hiểu là lệnh, không phải là từ trước.

Vì vậy, bash sau đó chạy nội trang của nó timemà không có đối số, được chấp nhận. Nó không tạo ra đầu ra, và chúng tôi thấy không có lỗi.

Lưu ý rằng:

`time`

thực sự chạy kết quả của tích timehợp, tức là nó chạy bất cứ thứ gì tích timehợp tạo ra trên thiết bị xuất chuẩn. Nhưng vì timebản thân nó không viết bất cứ điều gì cho thiết bị xuất chuẩn, nó dường như hoạt động.

Cuối cùng, nó đã được lưu ý rằng điều này hoạt động:

time ; ; date

Điều mà tôi không thể giải thích, thật đáng buồn :)


Tôi nghĩ rằng lời giải thích của bạn là tốt hơn, nhưng nó vẫn có vẻ kỳ lạ với tôi. ;datecho bash: syntax error near unexpected token ;, nhưng time ;datecho bash: syntax error near unexpected token date, vì vậy có vẻ như bash không coi lệnh sau thời gian dựng sẵn là "; ngày". Thật thú vị, time ; ; datelàm việc.
sắp xếp

yup, cảm ơn @arrange, nó khá lạ Tôi sẽ cập nhật câu trả lời một chút.
cdmackay

ok, @arrange, đã viết lại. Vẫn không thể giải thích cuối cùng của bạn mặc dù ... thở dài.
cdmackay

@cdmackay Bạn đang trộn lẫn backticks và dấu ngoặc kép. Bằng cách trích dẫn 'time' nó mất ý nghĩa của nó như là một từ dành riêng. Backticking nó làm cho nó thực thi trong một subshell có đầu ra được ghép vào lệnh. Điều này không có gì để làm với các cuộc thảo luận. Như một vấn đề thực tế, ví dụ của bạn `time\';datechứng minh điều ngược lại với yêu cầu của bạn: điều này sẽ gây ra lỗi bởi lý luận của bạn vì /usr/bin/timeyêu cầu một đối số. Lý do nó không phải là vì trong phần con mà nó thực thi nó là từ dành riêng timemột lần nữa.
zwets

@arrange Cả hai đều là lỗi cú pháp và cả hai đều được báo cáo là ở gần cùng một vị trí, vì vậy tôi không thấy sự không nhất quán ở đó. Khi nó vào vùng lỗi cú pháp, bạn không thể mong muốn trình phân tích cú pháp biết được lối thoát của nó. Nếu bạn yêu cầu trình phân tích cú pháp, thì nó phải biết không chỉ cú pháp hợp pháp, mà cả cú pháp của mọi cấu trúc bất hợp pháp có thể, theo định nghĩa là không thể.
zwets
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.