Terminal borked sau khi gọi Vim với xargs


30

Đôi khi tôi đã thử gọi Vim bằng cách sử dụng xargs, như thế này:

find . -name '*.java' | xargs vim

Những loại công trình:

  1. Khi Vim ra mắt, tôi thấy một chút cảnh báo sau đây:

    Vim: Warning: Input is not from a terminal
    
  2. Chỉnh sửa tác phẩm - :filesliệt kê chính xác tất cả các .javatệp như mong đợi.
  3. Tôi có thể tiết kiệm và bỏ thuốc lá.

Tuy nhiên, sau khi thoát Vim, thiết bị đầu cuối của tôi bị hỏng:

  • Bất cứ điều gì tôi gõ tại dấu nhắc shell không được lặp lại.
  • Lợi nhuận vận chuyển hoàn toàn không xuất hiện và nguồn cấp dữ liệu đôi khi chỉ xuất hiện.

Điều này diễn ra cho đến khi tôi đưa ra một reset(1)lệnh để khởi tạo lại thiết bị đầu cuối.

Đây có phải là một lỗi Vim, hoặc có một lời giải thích thỏa đáng hơn cho lý do tại sao nó tương tác với thiết bị đầu cuối như vậy? Tôi đã thấy điều đó xảy ra trên Vim cho đến phiên bản 7.3 (phiên bản dường như không quan trọng) trên Linux và các Thông báo khác nhau.

Tôi biết một cách giải quyết, cụ thể là vim $(find . -name '*.java'). Cách giải quyết khác sẽ được hoan nghênh, mặc dù đó không phải là câu hỏi chính của tôi.


Tôi mong muốn được lấp đầy trang web này với càng nhiều câu hỏi càng tốt, nhưng câu hỏi đó đã được trả lời hàng chục lần trong nhiều năm qua trên SO / SU và các nơi khác: xargssử dụng một hình nộm stdinkhông thể được Vim sử dụng và phá vỡ mọi thứ sau đó
romainl

1
@romainl Tôi không hoạt động trên các trang web đó và tôi chưa bao giờ thấy nó được hỏi ở đó - trung thực.
200_success

Liên quan: superuser.com/questions/336016/ - có lẽ ai đó có thể cô đọng những câu trả lời hàng đầu cho một câu trả lời tuyệt vời.
muru

2
Câu hỏi tuyệt vời - điều này đã xảy ra với tôi nhiều lần. Ngoài ra, tôi không sử dụng bất kỳ trang web SO nào khác - nếu nó liên quan đến vim, tôi muốn tìm thấy nó ở đây.
craigp

Câu trả lời:


21

Điều này xảy ra khi vim được gọi và nó được kết nối với đầu ra của đường ống trước đó, thay vì đầu cuối và nó nhận được đầu vào bất ngờ khác nhau (như NUL). Điều tương tự xảy ra khi bạn chạy : vim < /dev/null, vì vậy resetlệnh trong trường hợp này sẽ giúp. Điều này được giải thích tốt bởi sự tham lam tại superuser .

Nếu bạn đang sử dụng findđể chuyển tên tệp để chỉnh sửa, bạn không cần xargs, chỉ cần sử dụng -exec, ví dụ:

find . -name '*.java' -exec vim {} +

Nếu bạn muốn sử dụng xargs, trên Unix / macOS, bạn nên sử dụng -otham số, như:

find . -name '*.java' | xargs -o vim

-oMở lại stdin dưới dạng / dev / tty trong tiến trình con trước khi thực hiện lệnh. Điều này rất hữu ích nếu bạn muốn xargs chạy một ứng dụng tương tác.

hoặc là:

find . -name "*.java" -type f -print0 | xargs -o -0 vim

Lưu ý: Sử dụng -print0/ -0sẽ hỗ trợ tên tệp với khoảng trắng.


find+ BSDxargs

Trên Unix / macOS, bạn có thể thử cách giải quyết sau:

find . -name '*.java' | xargs -J% sh -c 'vim < /dev/tty $@'

Bạn cũng có thể sử dụng cú pháp thay thế lệnh , ví dụ:

vim $(find . -name '*.java')
vim `find . -name '*.java`

Hoặc sử dụng GNU parallelthay vì xargsbuộc phân bổ tty, ví dụ:

find . -name '*.java' | parallel -X --tty vi

Lưu ý: paralleltrên Unix / OSX sẽ không hoạt động vì nó có các tham số khác nhau và nó không hỗ trợ tty.

Nhiều lệnh phổ biến khác cũng cung cấp phân bổ giả (như -ttrong ssh), vì vậy hãy kiểm tra trợ giúp.

Đề xuất khác sẽ được sử dụng:

Liên quan:


GNU của tôi xargskhông có -J. Đó dường như là một tùy chọn MacOS (BSD) không có trong phiên bản GNU.
Tạm dừng cho đến khi có thông báo mới.

12

Đề xuất giải pháp: sử dụng bộ đệm làm trình điều hướng hệ thống tập tin

Sử dụng vim -lệnh để đọc danh sách các đường dẫn từ stdin. Vim's :help --giải thích điều này: 1

Bắt đầu chỉnh sửa một bộ đệm mới, chứa đầy văn bản được đọc từ stdin. Các lệnh thường được đọc từ stdin bây giờ sẽ được đọc từ stderr. Thí dụ:

find . -name "*.c" -print | vim -

Sau đó, bạn có thể sử dụng gfhoặc Ctrl-wCtrl-fđể điều hướng đến tệp trong cùng một bộ đệm hoặc trong một cửa sổ phân chia mới tương ứng.

Đề xuất giải pháp: danh sách đối số

Một cách tuyệt vời khác là sử dụng danh sách đối số của Vim. Các :argadd **/*.javalệnh sẽ cư danh sách đối số Vim với tất cả các file java tìm thấy bên trong thư mục hiện đệ quy. Sau đó, bạn có thể sử dụng :next:prevđể di chuyển giữa các tệp.


1 Cái đầu tiên -cho Vim bạn muốn tìm kiếm trợ giúp cho tùy chọn dòng lệnh, thứ hai thực sự là cờ dòng lệnh bạn đang tìm kiếm. Đọc :help help-contextđể biết thêm thủ thuật như thế này.


8

Ngoài ra reset, bạn có thể thử:

stty sane

mà cũng nên làm cho thiết bị đầu cuối của bạn có thể sử dụng một lần nữa.

Xem ở đây để giải thích. Và bằng cách nào đó, điều này có thể được coi là một hành vi sai trái vim, ít nhất Neovim không có vấn đề này vào lúc này.


Điều này không trả lời chính xác câu hỏi, nhưng nó đã giúp tôi, nên +1.
Tái lập lại Monica iamnotmaynard

Điều này KHÔNG trả lời câu hỏi của tôi;) Mặc dù sau khi đọc OP nhiều hơn, tôi cũng đoán resetvậy.
Sridhar Sarnobat

1

Nguyên nhân là do xargsbộ stdinđến /dev/null, trong khi vimnhu cầu stdin/dev/tty.


xargsGiải pháp BSD (ví dụ Mac):

echo -e 'file1\nfile2' | xargs -o vim

-ođặt stdintiến trình con của xarg ( vimtrong trường hợp này) thành dev/tty.


xargsGiải pháp GNU (ví dụ Linux):

GNU xargskhông có -otùy chọn. Thay vào đó, bạn sẽ phải sử dụng một cách giải quyết phức tạp hơn. (Lưu ý: Điều rất quan trọng là có zerochuỗi dấu , đừng quên nó.)

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

Bạn cũng có thể biến nó thành bí danh:

alias vimin='xargs bash -c '\''</dev/tty vim "$@"'\'' zero'
echo -e 'file1\nfile2' | vimin

Giải thích chi tiết về giải pháp GNU xargs

Hãy phá vỡ nó từng bước một:

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

1. xargschỉ cần nối thêm stdinvào cuối chuỗi, vì vậy xargssẽ thực hiện điều này:

    bash -c '</dev/tty vim "$@"' zero file1 file2

2. Định dạng cho bash -cbash -c 'COMMAND_STRING' $0 $1 $2 etc.

"$@"mở rộng đến các tham số vị trí "$1", "$2", v.v. Nó không bao gồm "$ 0" vì đó là tham số đặc biệt cho tên tập lệnh, không phải là tham số vị trí. Đây là lý do tại sao chúng ta cần thêm chuỗi giả zero(nó có thể là bất kỳ chuỗi nào) để thay thế $0. Nếu không, bạn sẽ mất tập tin đầu tiên.

Vì vậy, sau khi bạn mở rộng "$@", bạn kết thúc với:

    bash -c '</dev/tty vim file1 file2' 

3. bash -csẽ thực thi LỆNH_STRING:

    </dev/tty vim file1 file2 

</dev/ttythiết lập stdinđể /dev/ttysao cho vimcó thể làm việc trong chế độ tương tác.


+1 Đây có vẻ là một bản sao của câu trả lời có số phiếu bầu cao nhất, nhưng thực tế không phải vậy. Trình $0giữ chỗ (ở đây "không") là chìa khóa.
Tạm dừng cho đến khi có thông báo mới.

0

Tôi đã tìm thấy tất cả những câu trả lời thiếu. Sau khi vật lộn với vấn đề xargs, cách đơn giản nhất - đối với tôi! - để thực hiện các tìm kiếm và mở này trên một hộp chung là như sau:

vim -O `grep -lir mySearchTerm *`

Tôi không có vấn đề gì khi sử dụng findvới xargsgrep, nhưng tôi thấy cú pháp khó chịu. Và là một lập trình viên hàng ngày sử dụng vimvà thiết bị đầu cuối như IDE của họ và liên tục tìm kiếm các tệp cho các thuộc tính, đây là những gì tôi đã và đang sử dụng.

Có một thời gian và địa điểm để find . -path ./node_modules -prune -o -name '*.js' | xargs grep -i mySearchTermkết hợp với mở tệp thông qua vim và các phương pháp khác. Đối với tôi, điều đó là hiếm khi.

Hy vọng điều này sẽ giúp được ai đó.


2
FWIW không nên sử dụng ký hiệu backticks kế thừa và sử dụng $(...)thay thế. Nó không quan trọng trong dòng lệnh của bạn như trong kịch bản nhưng tôi nghĩ vẫn tốt hơn khi sử dụng nó trong câu trả lời của bạn :) (tham khảo tại đâytại đây )
statox
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.