Zsh có thể truy cập vào thiết bị xuất chuẩn của chương trình chạy cuối cùng không?


14

Tôi thường sử dụng findhoặc locateđể tìm hiểu về các con đường.

(~) locate foobar.mmpz
/home/progo/lmms/projects/foobar.mmpz

Bước tiếp theo thường là mở hoặc thao tác các tệp. Trong một trường hợp hạnh phúc như trên, tôi có thể làm điều này:

(~) ls `!!`
ls `locate foobar.mmpz`
/home/progo/lmms/projects/foobar.mmpz

Nhưng không ai quá hạnh phúc khi có nhiều dòng đầu ra, một số trong đó có thể không phải là đường dẫn hoặc thứ gì đó khác. Bên cạnh đó, việc chạy lại các lệnh có khả năng gây lãng phí cũng không phải là điều thanh lịch.

Có cách nào để nối zsh để lưu thiết bị xuất chuẩn vào một mảng để thao tác sau này không? Rốt cuộc, công việc của shell là chuyển hướng các luồng đến người dùng. Tôi nghĩ rằng nó có thể lưu trữ N dòng đầu tiên và N cuối cùng trong một biến để sử dụng ngay sau đó, như $?và các dòng khác.

Ok , điều này khá tuyệt: /unix//a/59704/5674 . Bây giờ tôi đang hỏi về bí quyết zsh (và chuyển mã sang zsh) để xử lý kiểu chụp này sau mỗi dòng chạy.


Đây thực sự không phải là công việc của shell để chuyển hướng luồng đến người dùng. Các ứng dụng ghi đầu ra của chúng vào thiết bị đầu cuối, vỏ không liên quan đến điều đó.
Stéphane Chazelas

@StephaneChazelas, nhưng công việc của shell là chuyển hướng các luồng vào các tệp theo yêu cầu của người dùng. Ngoài ra còn có công thức cho zsh rằng stderr màu đỏ để tách nó ra khỏi thiết bị xuất chuẩn. Tôi nghĩ rằng điều đó cho thấy vai trò của shell trong các vấn đề phát trực tuyến.
unperson325680

Có, bạn có thể làm điều đó bằng cách sử dụng screenhoặc scriptvà các móc nối premd và preexec.
Stéphane Chazelas

Câu trả lời:


6

Không có tính năng chụp đầu ra từ màn hình trên hầu hết các trình giả lập thiết bị đầu cuối. Tôi dường như nhớ lại tác giả của xterm (trình giả lập thiết bị đầu cuối tham chiếu trực tuyến) nói rằng nó sẽ khó thực hiện. Ngay cả nếu điều đó là có thể, vỏ sẽ phải theo dõi vị trí của dấu nhắc cuối cùng.

Vì vậy, bạn sẽ không thoát khỏi việc phải chạy lại lệnh, trừ khi bạn sử dụng cơ chế thủ công, dành riêng cho thiết bị đầu cuối, chẳng hạn như dán sao chép bằng chuột trong xterm hoặc với bàn phím trong Màn hình.

Sẽ rất không thực tế khi shell tự động nắm bắt đầu ra của các lệnh, bởi vì nó không thể phân biệt giữa các lệnh có thiết bị đầu cuối phức tạp và tương tác người dùng với các lệnh chỉ đơn giản là xuất các ký tự có thể in được.

Bạn có thể chạy lại lệnh và nắm bắt đầu ra của nó. Có nhiều cách khác nhau để làm mỗi. Để chạy lại lệnh, bạn có thể sử dụng:

  • !! thay thế lịch sử - thuận tiện nhất để gõ;
  • fc -e -, có thể được sử dụng trong một chức năng.

Để nắm bắt đầu ra, bạn có thể sử dụng thay thế lệnh hoặc một chức năng như sau:

K () {
  lines=("${(f@)$(cat)}")
}
!! |K

Cái này đặt linesmảng thành đầu ra của lệnh được dẫn vào nó.


Như chỉ thị. Bây giờ tôi nhận ra rằng giải thích tốt rằng một cách tiếp cận hoàn toàn tự động là quá khó, điều tốt nhất thứ hai là một cái gì đó giống như Kcủa bạn.
unperson325680

3

Đây là phần đầu tiên của một cái gì đó để đặt dòng đầu ra cuối cùng trong một biến được gọi là $lastline.

precmd () {                                                                                                                                                                                                        
    exec 2>&- >&-
    lastline=$(tail -1 ~/.command.out) 
    sleep 0.1   # TODO: synchronize better
    exec > /dev/tty 2>&1
}

preexec() {
    exec > >(tee ~/.command.out&)
}

Cái này sử dụng preexechook của zsh để chạy execvới teeđể lưu một bản sao của stdout của lệnh, sau đó sử dụngprecmd để đọc đầu ra được lưu trữ và khôi phục stdout để chỉ là thiết bị đầu cuối để hiển thị lời nhắc.

Nhưng nó vẫn cần một số công việc. Ví dụ: vì thiết bị xuất chuẩn không còn là thiết bị đầu cuối, các chương trình như vimless không hoạt động đúng.

Có một số thông tin liên quan hữu ích trong những câu hỏi này:


Có, có lẽ cách tiếp cận tự động 100% sẽ không hiệu quả. Có nhiều execcuộc gọi trong mã, là lệnh chạy nhiều lần hay tôi bị bắt trong ngữ nghĩa đặc biệt?
unperson325680

execkhông có tên chương trình chỉ đặt các chuyển hướng.
Mikel

2

Bạn có thể làm điều này bằng cách chỉ dẫn kết quả của bạn đến tee , điều này chỉ lưu kết quả đầu ra vào một tệp và hiển thị nó cùng một lúc.

Vì vậy, ví dụ, bạn có thể làm điều này, cho thấy đầu ra của bạn như bình thường, nhưng cũng lưu nó vào tệp /tmp/it

locate foobar.mmpz | tee /tmp/it

sau đó chọn tập tin đó và grep nó để chọn mọi thứ, vd

cat /tmp/it | grep progo | grep lms

Sau đó, để sử dụng nó, bạn có thể làm điều này:

vi $(!!)


2

Tôi đã đưa ra giải pháp nửa nướng này:

alias -g ___='"$(eval "$(fc -ln -1)" | tail -n 1)"'

Điều này cho phép bạn viết ___tại bất kỳ điểm nào trong dòng lệnh. Lệnh trước sẽ được chạy lại và ___sẽ được thay thế bằng dòng cuối cùng của đầu ra. Ví dụ sử dụng:

$ touch foo bar baz
$ ls -1
bar
baz
foo
$ vim ___

Lệnh cuối cùng sẽ được mở rộng thành vim foo.

Điều này không có một số cạnh sắc nét!

  • Nếu bạn bao gồm ___trong một lệnh nhưng lệnh trước đó cũng bao gồm a ___, shell sẽ bị treo trong một số trạng thái kỳ lạ. Bạn có thể thoát khỏi trạng thái này ngay lập tức với Ctrl- C.

  • Bạn cũng không thể nhấn Tabđể mở rộng ___, giống như bạn có thể với !$và các công trình khác.

  • Một số lệnh sẽ hiển thị đầu ra khác nhau khi chúng được chạy thông thường, và khi chúng được gắn vào một đường ống. (So ​​sánh đầu ra của lsls | cat.) Nếu lệnh được kích hoạt ___là một trong số này, bạn có thể sẽ chạy một lệnh khác so với dự kiến.

  • Và tất nhiên, nếu bạn muốn làm một cái gì đó với một dòng đầu ra khác với dòng cuối cùng, điều này sẽ không giúp bạn.

Tôi đã chọn tên này ___vì đó là thứ tôi chưa bao giờ muốn đưa vào dưới dạng từ trong dòng lệnh, thậm chí không phải là đối số. Bạn có thể chọn một tên khác, nhưng chú ý không chọn một cái gì đó có thể được mở rộng cho bạn vô tình.

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.