Làm thế nào để sử dụng grep output làm đường dẫn cho cd?


9

Làm thế nào tôi có thể dẫn grepđầu ra như là một đối số cho cdlệnh?

Ví dụ:

[root@xxx xxx]# pip install django | grep '/usr.*'  
Requirement already satisfied (use --upgrade to upgrade): django in   /usr/lib64/python2.7/site-packages

Ở đây /usr/lib64/python2.7/site-packagesđược tô sáng và tôi muốn chuyển chuỗi này đến cd.

Câu trả lời:


16

Sử dụng thay thế lệnh của Bash $(), bạn cũng cần -ovới grep để chỉ chọn phần phù hợp:

cd "$(pip install django | grep -o '/usr.*')"

Lưu ý rằng mặc dù bạn sẽ thoát khỏi trường hợp này nhưng bạn phải luôn luôn thay thế lệnh bằng dấu ngoặc kép để shell không thực hiện phân tách từ trên khoảng trắng (theo không gian mặc định, tab và dòng mới, tùy thuộc vào IFSbiến trong trường hợp bash).


9

Tùy thuộc vào những gì bạn làm và không biết trước về những gì pipsẽ xuất ra, bạn có thể quyết định grepcho một cái gì đó khác hơn /usr.*.

Nếu bạn biết thư mục bắt đầu bằng/usr (và nó xuất hiện ở cuối dòng đầu ra từ pipđó và /usrnó không xuất hiện ở bất kỳ đâu trên dòng trước tên thư mục), thì đó là một lựa chọn tốt; Câu trả lời của heemayl cho bạn biết làm thế nào.

Nếu lý do bạn biết nó bắt đầu /usrlà vì bạn vừa chạy lệnh và biết thư mục bạn muốn thay đổi, tôi đề nghị giải pháp đơn giản hơn là chạy lệnh cd /usr/lib64/python2.7/site-packages. Đây là cách gõ ít hơn ngay cả khi bạn không sử dụng hoàn thành tab .

Mặt khác, bạn có thể chọn một biểu thức chính quy khác nhau tùy thuộc vào những gì bạn biết về đầu ra được phân tích cú pháp. Tất cả các lựa chọn thay thế bên dưới vẫn giả sử tên thư mục xuất hiện ở cuối dòng, nhưng các giả định khác thì khác.

Nếu bạn biết tên thư mục là tuyệt đối (nghĩa là bắt đầu bằng a /) và không /xuất hiện trên dòng trước tên thư mục , bạn có thể sử dụng cùng biểu thức chính quy như trong câu trả lời của heemayl nhưng /thay vì /usr:

cd "$(pip install django | grep -o '/.*')"

Điều này khớp với /số 0 hoặc nhiều hơn ( *) của bất kỳ ký tự nào ( .).

Nếu bạn biết tên thư mục không chứa khoảng trắng ngang (không có khoảng trắng hoặc tab) và xuất hiện ở cuối dòng , bạn có thể sử dụng:

cd "$(pip install django | grep -oP '[^\h]+$')"

Ở đây, tôi đã sử dụng một biểu thức chính quy Perl ( -P) vì \hchữ viết tắt (for [:blank:]) giúp việc này dễ đọc và dễ đọc hơn so với biểu thức chính quy mở rộng tương đương ( -E). Điều này khớp với một hoặc nhiều ( +) của bất kỳ ký tự nào trong một lớp các ký tự ( [ ]) không phải là ( ^) một khoảng trắng hoặc tab ( \h).

Nếu bạn biết tên thư mục của mình ngay lập tức được inbao quanh bởi khoảng trắng ngang (nghĩa là được đệm ở cả bên trái và bên phải với khoảng trống) và đây là lần xuất hiện duy nhất intrên dòng , bạn có thể sử dụng:

cd "$(pip install django | grep -oP '\hin\h+\K.+')"

Điều này sử dụng xác nhận nhìn phía sau dương (0 \K) để khớp với một hoặc nhiều ký tự ( .+) xuất hiện sau dấu cách hoặc tab ( \h) invà một hoặc nhiều khoảng trắng hoặc tab ( \h+) khác mà không thực sự bao gồm invà khoảng trắng xung quanh nó trong trận đấu. Các xác nhận nhìn xung quanh là một tính năng của biểu thức chính quy Perl.

Mô hình cũng sẽ hoạt động, nhưng chúng ta chỉ cần tìm một ô trống trước đó , bất kể có bao nhiêu mặt. Ngược lại, chúng ta phải khớp tất cả các khoảng trống sau , nếu không chúng sẽ bị loại bỏ và chúng sẽ được khớp như một phần của tên thư mục.\h+in\h+\K.+inin\K

Nếu bạn biết tên thư mục ngay trước dòng xuất hiện cuối cùng của dòng intiếp theo là khoảng trắng ngang , bạn có thể sử dụng:

set +H
cd "$(pip install django | grep -oP '\hin\h+(?!.*\hin\h.*)\K.*')"
set -H

Ở đó, bản thân khẳng định nhìn phía sau dương có độ rộng bằng không chứa khẳng định nhìn phía trước âm (0 (?! )).

Sự !xuất hiện theo cách khó thoát ra một cách thanh lịch; phương pháp tôi đã sử dụng để ngăn nó kích hoạt mở rộng lịch sử shell trước khi được truyền tới greplà tạm thời vô hiệu hóa mở rộng lịch sử ( set +H) trước khi chạy lệnh và kích hoạt lại nó ( set -H) sau đó. Nếu bạn đang sử dụng tập lệnh này trong tập lệnh và tập lệnh của bạn không chứa set -H, bạn không cần thực hiện việc này vì mở rộng lịch sử chỉ được bật tự động khi trình bao chạy tương tác.

Cuối cùng, lưu ý rằng không ai trong số này, cũng không trả lời heemayl của , đang thực sự đường ống đầu ra của grepđể cd(mặc dù sản lượng pipvẫn đang được cấp nước tập trung để grep). Thay vì đường ống , công cụ thích hợp cho công việc này là thay thế lệnh .


Tất nhiên, nếu bạn muốn có được kỹ thuật , shell sử dụng một đường ống bên trong để đọc đầu ra lệnh.
Random832

@ Random832 Điểm tốt - Tôi đã chỉnh sửa một chút khi xem xét điều này. Btw, bạn có biết việc sử dụng các đường ống "dưới mui xe" trong thay thế lệnh có thể được dựa vào không? Hay đó là một chi tiết triển khai có khả năng có thể được thực hiện khác nhau trong một phiên bản bash khác, trong tương lai? (Tất nhiên, trong thực tế, tôi hiểu đó là cách tốt nhất để làm điều đó và do đó không thể thực hiện theo cách khác.)
Eliah Kagan

1
Không, nó không được bảo đảm, về mặt lý thuyết, một shell có thể sử dụng tệp fifo hoặc temp, mặc dù không có lý do gì.
Random832

Bạn có chắc chắn về việc mở rộng lịch sử? Các ký tự duy nhất có thể chặn nó là ` and '`và bạn đã sử dụng các dấu ngoặc đơn xung quanh biểu thức grep.
muru

1
@muru Vâng, nó được mở rộng. Tôi cũng không nhận thấy, nhưng phát hiện ra khi tôi thử nó. Không !có trích dẫn với '-quote, vì chính '-quote được trích dẫn. Độ phức tạp của lệnh giúp dễ dự đoán sai hiệu quả của nó, nhưng rõ ràng do thứ tự mở rộng ( !là sớm) nên nó kết thúc hoạt động như x=foo; echo "'$x'"(-> 'foo'). Loại bỏ các câu hỏi bên ngoài "sẽ gây ra !được 'trích dẫn và ngăn chặn việc mở rộng lịch sử, nhưng sau đó cd sẽ thất bại nếu thư mục có khoảng trắng trong tên của nó.
Eliah Kagan
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.