Làm thế nào để sử dụng backtick-mở rộng để điền vào đối số?


11

Từ trợ giúp :help backtick-expansion:

On Unix and a few other systems you can also use backticks for the file name
argument, for example:
    :next `find . -name ver\\*.c -print`
    :view `ls -t *.patch  \| head -n1`
The backslashes before the star are required to prevent the shell from
expanding "ver*.c" prior to execution of the find program.  The backslash
before the shell pipe symbol "|" prevents Vim from parsing it as command
termination.

Nếu tôi gõ lệnh được lấy từ trợ giúp, tôi sẽ gặp lỗi:

:next `find . -name ver\\*.c -print
E79: Cannot expand wildcards  

Tại sao ví dụ từ trợ giúp sử dụng hai dấu gạch chéo ngược thay vì một và tại sao nó không hoạt động?

Công việc sau:

  • Nếu tôi loại bỏ một trong hai dấu gạch chéo ngược để bảo vệ ngôi sao khỏi bị mở rộng bởi lớp vỏ trước findchương trình:

    :next `find . -name ver\*.c -print`
    
  • Nếu tôi loại bỏ cả dấu gạch chéo ngược và đặt dấu ngoặc đơn xung quanh mẫu ver*.c:

    :next `find . -name 'ver*.c' -print`
    

Cho đến thời điểm này, quy tắc dường như là:
nếu lệnh shell của bạn chứa một ngôi sao và bạn không muốn shell mở rộng nó trước lệnh, đặt một dấu gạch chéo ngược trước nó hoặc đặt dấu ngoặc đơn xung quanh mẫu .

Nhưng sự giúp đỡ đưa ra một ví dụ khác:

:view `ls -t *.patch  \| head -n1`

Lệnh này hoạt động mà không cần sửa đổi, không cần trích dẫn đơn, không cần dấu gạch chéo ngược.
Tôi cho rằng lý do tại sao nó hoạt động là vì lslệnh (trái với -nameđối số của findlệnh) chấp nhận nhiều đối số tệp và thấy không có vấn đề gì với việc mở rộng shell *.patch.

Bây giờ, giả sử tôi muốn tìm tất cả các tệp có phần mở rộng .confbên trong /etcthư mục và đặt đầu ra của findđể grepchỉ nhận các kết quả khớp có chứa chuỗi input.
Trong shell, từ bất kỳ thư mục làm việc, tôi sẽ gõ:

find /etc -name '*.conf' | grep input

Và nó sẽ làm việc.

Trong vim, tôi sẽ gõ cùng một lệnh đặt backticks xung quanh nó và dấu gạch chéo ngược phía trước biểu tượng đường ống để ngăn vim diễn giải nó như là chấm dứt lệnh:

:next `find /etc -name '*.conf' \| grep input`

Và nó hoạt động.

Bây giờ, nếu tôi gõ cùng một lệnh mà không có ống dẫn và grep input, tôi gặp lỗi:

:next `find /etc -name '*.conf'`
E79: Cannot expand wildcards

Tại sao có lỗi trong trường hợp này mặc dù tôi đã bảo vệ ngôi sao bằng dấu ngoặc đơn?
Và tại sao bây giờ có lỗi, nhưng không chỉ trước đây với đường ống và grep input?

Để thử hiểu, tôi đã đưa ra một lệnh đơn giản hơn:

find . -name '*.conf'

Nó tìm kiếm tất cả các tập tin với phần mở rộng .conftrong thư mục làm việc. Lệnh hoạt động trong shell.

Để kiểm tra nó trong vim, tôi đã gõ: :next `find . -name '*.conf'`
Và nó hoạt động. Trong trường hợp này, dấu chấm là viết tắt của thư mục làm việc hiện tại của tôi như được hiển thị bởi lệnh Ex :pwdlà thư mục chính của /home/usernametôi kể từ khi tôi khởi chạy phiên vim từ nó.

Tại sao nó hoạt động khi tôi yêu cầu tìm kiếm trong thư mục làm việc hiện tại trong khi nó không hoạt động khi tôi yêu cầu tìm kiếm trong một thư mục tùy ý như /etc?

Bây giờ, nếu tôi thay đổi thư mục làm việc của mình từ /home/usernamesang /etcbằng lệnh vim Ex :cd /etcvà thử lại lệnh tương tự như trước đây, một lần nữa nó lại lỗi:

:next `find . -name '*.conf'`
E79: Cannot expand wildcards

Tại sao cùng một lệnh hoạt động khi tôi trong thư mục nhà của tôi mà không phải khi tôi ở trong /etc?

Tôi chắc chắn có một số logic, nhưng tôi không thể tìm thấy một.

Cú pháp chung và chính xác để điền vào danh sách đối số bằng lệnh shell tùy ý (chứa một ngôi sao, một đường ống, tìm kiếm trong bất kỳ thư mục nào từ bất kỳ thư mục làm việc nào)?

Tôi đang sử dụng phiên bản vim 7.4.942 và zsh là vỏ mặc định của tôi. Tôi đã thử nghiệm các lệnh này với tối thiểu các khởi tạo ( vim -u NORC -N) từ bash cũng như từ zsh.

Tôi có cần cấu hình vim để gọi bash và không zsh không?


Tôi tự hỏi nếu bạn đã cố gắng bắt đầu vim với tất cả các tệp được truyền dưới dạng đối số? Ý tôi là đại loại như:vim $(find . -name ver*.c)
Vlad GURDIGA

@VladGURDIGA Tôi vừa cố gắng và chúng đều hoạt động như mong đợi từ vỏ: vim $(find . -name ver\*.c -print), vim $(ls -t *.patch | head -n1), vim $(find /etc -name '*.conf' | grep input), vim $(find /etc -name '*.conf'),vim $(find . -name '*.conf')
Saginaw

@VladGURDIGA Nhưng tôi muốn biết làm thế nào để điền vào danh sách mà không bỏ phiên hiện tại vì tôi thường chỉ có một. Tôi cũng có thể di chuyển trong shell, tìm kiếm một nhóm tệp và gửi chúng đến máy chủ Vim (với đối số --remote, xem: vi.stackexchange.com/a/5618/4939 ) nhưng tôi tò mò muốn biết làm thế nào để làm điều đó trực tiếp từ phiên hiện tại. Nếu điều đó là không thể, điều đó tốt, nhưng sau khi đọc trợ giúp thì dường như điều đó có thể được thực hiện. Nếu có, tôi muốn hiểu tại sao vim phản ứng rất khác với các lệnh tương tự.
saginaw

Này, có vẻ như trong lệnh mẫu đầu tiên bạn đang thiếu backtick đóng. ;) Ngoài ra, tôi đoán ví dụ từ trợ giúp sử dụng hai dấu gạch chéo ngược thay vì một để ngăn chặn sự mở rộng vỏ, như được giải thích ở đây: unix.stackexchange.com/q/104260/23669 .
Vlad GURDIGA

Trong trường hợp find /etc -name '*.conf'không hoạt động, tôi nghĩ rằng một số tên vui nhộn xuất phát từ lệnh đó, và, đây có thể là lý do tại sao nó hoạt động khi được dẫn qua grep.
Vlad GURDIGA

Câu trả lời:


6

Tôi vẫn không biết cách sử dụng mở rộng backtick để điền vào danh sách đối số bằng lệnh shell tùy ý, tuy nhiên tôi đã tìm thấy một cách giải quyết.

Từ :help `=:

You can have the backticks expanded as a Vim expression, instead of as an
external command, by putting an equal sign right after the first backtick,
e.g.:
    :e `=tempname()`
The expression can contain just about anything, thus this can also be used to
avoid the special meaning of '"', '|', '%' and '#'.  However, 'wildignore'
does apply like to other wildcards.

Vì vậy, thay vì mở rộng trực tiếp một lệnh shell như thế này:

:args `shell command`

Chúng ta có thể gửi lệnh shell đến hàm Vim systemlist()và sử dụng thanh ghi biểu thức =để mở rộng biểu thức kết quả như thế này:

:args `=systemlist("shell command")`

Để lưu một số tổ hợp phím, tôi đã xác định lệnh Ex sau trong vimrc của mình ( :PAđối với Danh sách đối số dân số):

command! -nargs=1 PA args `=systemlist(<q-args>)`

Và đã thử nghiệm nó với các lệnh shell khác nhau:

:PA find . -name ver\*.c -print 2>/dev/null
:PA find . -name 'ver*.c' -print 2>/dev/null
:PA ls -t *.patch  | head -n1
:PA find /etc -name '*.conf' 2>/dev/null | grep input
:PA find /etc -name '*.conf' 2>/dev/null
:PA find . -name '*.conf' 2>/dev/null

Cho đến nay nó hoạt động như mong đợi và lệnh có thể được gõ như trong vỏ (không cần phải thoát khỏi đường ống chẳng hạn).
Nó có vẻ phù hợp và đáng tin cậy hơn mở rộng backtick trực tiếp.

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.