Як використовувати греп-вихід як шлях для CD?


9

Як я можу grepподати висновок як аргумент cdкоманди?

Наприклад:

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

Тут /usr/lib64/python2.7/site-packagesвиділено, і я хочу передати цей рядок cd.

Відповіді:


16

Використовуйте підстановку команди Bash $(), вам також потрібно -oз grep вибрати лише відповідну частину:

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

Зауважте, що хоч ви йдете в цьому випадку, але завжди слід додавати підстановку команди подвійними лапки, щоб оболонка не виконувала розбиття слів на пробіли (за замовчуванням пробіл, вкладка та новий рядок, залежить від IFSзмінної у випадку bash).


9

Залежно від того, що ви робите, і не знаєте заздалегідь про те, що pipвийде, ви можете зважитися на grepщось інше, ніж /usr.*.

Якщо ви знаєте, що каталог починається з/usr (і що він з’являється в кінці рядка виводу з pip, і /usrвін не з’являється ніде в рядку перед назвою каталогу), то це прекрасний вибір; Відповідь heemayl говорить вам, як.

Якщо причина ви знаєте , що починається з /usrте , що ви просто запустити команду і знати директорію , яку ви хочете змінити, я пропоную просте рішення , виконавши команду cd /usr/lib64/python2.7/site-packages. Це менше вводити текст, навіть якщо ви не використовуєте доповнення вкладки .

В іншому випадку ви можете вибрати інше регулярне вираження залежно від того, що ви знаєте про вихідний аналіз. Усі наведені нижче альтернативи все ще припускають, що ім’я каталогу відображається в кінці рядка, але інші припущення змінюються.

Якщо ви знаєте, що ім'я каталогу абсолютне (тобто починається з а /) і /в рядку перед іменем каталогу не відображається , ви можете використовувати те саме, що і у відповіді heemayl, але /замість /usr:

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

Це відповідає /наступному нулю або більше ( *) будь-якого символу ( .).

Якщо ви знаєте, що ім'я каталогу не містить горизонтальної пробілу (немає пробілів і вкладок) і відображається в кінці рядка , ви можете використовувати:

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

Тут я використав regexp ( -P) Perl, тому що \hабревіатура (for [:blank:]) робить це легше набирати та читати, ніж еквівалентний розширений regexp ( -E). Це відповідає одному або більше ( +) будь-яких символів у класі символів ( [ ]), який не є ( ^) пробілом чи вкладкою ( \h).

Якщо вам відомо, що ім'я каталогів безпосередньо передує inоточеним горизонтальним пробілом (тобто, з лівою та правою сторонами прокладені пробілами), і що це єдине подібне виникнення inу рядку , ви можете використовувати:

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

При цьому використовується позитивне твердження "нульової ширини" ( \K), щоб відповідати одному або більше символів ( .+), що з'являються після пробілу чи вкладки ( \h) in, та іншого одного або декількох пробілів чи вкладок ( \h+), не включаючи фактично inі порожні пробіли оточуючи його в матчі. Оглядові твердження - особливість регулярних виразів Perl.

Шаблон також спрацював би, але нам потрібно лише шукати один бланк раніше , незалежно від кількості присутніх. На відміну від цього, ми повинні відповідати всі пробіли після , інакше вони не будуть відкинуті, і вони будуть узгоджені як частина імені каталогу.\h+in\h+\K.+inin\K

Якщо вам відомо, що ім'я каталогу безпосередньо передує останньому появі рядка, inа потім горизонтальним пробілом , ви можете використовувати:

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

Там позитивне заперечне твердження нульової ширини містить негативне твердження вперед-нульової ширини ( (?! )).

У !з'являється таким чином, щоб бути важко уникнути елегантно; метод, який я використав для запобігання його запуску розширення історії оболонки перед передачею, grep- тимчасово відключити розширення історії ( set +H) перед запуском команди та повторно включити її ( set -H) після цього. Якщо ви використовуєте це в сценарії, а ваш скрипт не містить set -H, робити це не потрібно, оскільки розширення історії вмикається автоматично лише тоді, коли оболонка працює в інтерактивному режимі.

Нарешті, зауважте, що жоден із них, ані відповідь геемайла , насправді не визначають результат виведення grepдо cd(хоча вихід pipдосі все ще виконується grep). Замість труб , відповідним інструментом для цього завдання є підміна команд .


Звичайно, якщо ви хочете отримати технічну форму, оболонка використовує трубу внутрішньо, щоб прочитати вихід команди.
Випадково832

@ Random832 Добре - я зважаючи на це трохи відредагував. До речі, чи знаєте ви, чи можна покластися на використання труб "під капотом" для заміни команд? Або це деталі реалізації, які потенційно можуть бути зроблені інакше в іншій, майбутній версії bash? (Звичайно, на практиці я розумію, що це найкращий спосіб зробити це, і тому навряд чи можна реалізувати інакше.)
Eliah Kagan

1
Ні, це не гарантується, теоретично оболонка може використовувати іменований файл fifo або temp, хоча для цього немає підстав.
Випадково832

Ви впевнені в розширенні історії? Єдині символи, які можуть його заблокувати, - це ` and "", і ви використовуєте одинарні лапки навколо виразу grep.
муру

1
@muru Так, це розширено. Я також не помічав, але дізнався, коли тестував. !Там не котирується з '-quotes, як '-quotes самі лапки. Складність команди полегшує неправильне передбачення її ефекту, але, мабуть, завдяки порядку розширень ( !рано), воно закінчується як x=foo; echo "'$x'"(-> 'foo'). Видалення зовнішніх "лапок призведе !до 'цитування і запобігає розширенню історії, але потім cd не вдасться, якщо каталог має пробіл у своєму імені.
Елія Каган
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.