Grep çıkışı cd yolu olarak nasıl kullanılır?


9

Nasıl yapabilirim boru grepargüman olarak çıktı cdkomutu?

Örneğin:

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

Burada /usr/lib64/python2.7/site-packagesvurgulanır ve bu dizeyi geçmek istiyorum cd.

Yanıtlar:


16

Bash'in komut değişikliğini kullanın $(), -osadece eşleşen bölümü seçmek için grep'e ihtiyacınız vardır:

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

Bu durumda kaçmanıza rağmen, komutun yerine her zaman çift tırnak işareti koymanız gerekir, böylece kabuk boşluklarda kelime bölme gerçekleştirmez (varsayılan olarak boşluk, sekme ve satırsonu, IFSduruma göre değişkene bağlıdır bash).


9

Ne yapacağınıza ve neyin pipçıkacağına dair önceden bilmediğinize bağlı olarak, grepbaşka bir şey için karar verebilirsiniz /usr.*.

Biliyorsanız dizin başlar/usr (ve ondan çıktı hattının sonunda görünen pipve bu /usrdizin adından önce satırda herhangi bir yerde görünmüyor), o İyi bir seçim; heemayl'ın cevabı size nasıl yapılacağını anlatır.

Eğer bununla başladığınızı bilmenizin nedeni/usr sadece komutu çalıştırmanız ve değiştirmek istediğiniz dizini bilmenizdir, komutu çalıştırmanın daha basit bir çözümünü öneririm cd /usr/lib64/python2.7/site-packages. Sekme tamamlama özelliğini kullanmasanız bile bu daha az yazımdır .

Aksi takdirde, ayrıştırılmakta olan çıktı hakkında bildiklerinize bağlı olarak farklı bir normal ifade seçebilirsiniz. Aşağıdaki tüm alternatifler hala dizin adının satırın sonunda göründüğünü varsayar, ancak diğer varsayımlar değişir.

Biliyorsanız dizin adı mutlaktır (yani bir ile başlar /) ve hiçbir /dizin adından önce on line görünür , sen aynı Regexp'i kullanabilirsiniz heemayl cevabı fakat /yerine /usr:

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

Bu , herhangi bir karakterin ( ) /ardından sıfır veya daha fazla ( *) ile eşleşir ..

Biliyorsanız dizin adı hiçbir yatay boşluk içeriyor (boşluk veya sekme) ve satırın sonunda görünür , şunları kullanabilirsiniz:

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

Burada bir Perl regexp ( -P) kullandım çünkü \h(for [:blank:]) kısaltması bu yazmayı ve okumayı eşdeğer bir genişletilmiş regexp ( -E) ' den daha kolay hale getirir . Bu, bir veya daha fazla (maçları +) karakterden oluşan bir sınıfı (içinde herhangi bir karakterin [ ]olduğu) değil ( ^) bir boşluk veya sekme ( \h).

Eğer t biliyorsanız o dizin adı derhal öncesinde inyatay boşluk ile çevrili (yani sol ve sağ boşluklar içeren hem yastıklı) ve bu bu sadece böyle bir durumdur insatırda , şunları kullanabilirsiniz:

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

Bu, boşluk veya sekmeden ( ) sonra görünen \Kbir veya daha fazla karakteri ( .+) ve gerçekte boşluklar içermeyen ve boşluklar olmadan başka bir veya daha fazla boşluk veya sekmeyi ( ) eşleştirmek için sıfır genişliğinde pozitif bir görünüm ( ) kullanır maçta onu çevreliyor. Etrafa bakma iddiaları Perl düzenli ifadelerinin bir özelliğidir.\hin\h+in

Desen de işe yarardı, ancak kaç tane mevcut olduğuna bakılmaksızın daha önce sadece bir boşluk aramamız gerekiyor . Buna karşılık, sonraki tüm boşluklarla eşleşmeliyiz , aksi takdirde atılmazlar ve dizin adının bir parçası olarak eşleştirilirler.\h+in\h+\K.+inin\K

Biliyorsanız dizin adı hemen hattın öncesinde son oluşumu inyatay Arkasında boşluk , şunları kullanabilirsiniz:

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

Burada sıfır genişlikli pozitif geriye dönük iddianın kendisi, sıfır genişlikli bir negatif ileriye dönük iddia ( (?! )) içerir.

!Zor diye bir biçimde görünür kaçmak için zarif; aktarılmadan önce kabuk geçmişi genişletmesini tetiklemesini önlemek için kullandığım yöntem , komutu çalıştırmadan önce grepgeçmiş genişletmeyi ( set +H) geçici olarak devre dışı bırakmak ve set -Hdaha sonra yeniden etkinleştirmek ( ). Bunu bir komut dosyasında kullanıyorsanız ve komut dosyanız içermiyorsa set -H, yalnızca bir kabuk etkileşimli olarak çalıştığında geçmiş genişletme otomatik olarak etkinleştirildiğinden bunu yapmanız gerekmez.

Son olarak, not bunların hiçbiri, ne de o heemayl cevabı , aslında çıktısının edilmektedir grepiçin cd(çıkış olsa pipyine yöneltilen ediliyor grep). Borulardan ziyade , bu iş için uygun araç komut ikamesidir .


Tabii ki, teknik almak istiyorsanız , kabuk komut çıkışını okumak için dahili olarak bir boru kullanır.
Random832

@ Random832 İyi bir nokta - Bunu dikkate alarak biraz düzenleme yaptım. Btw, komut yerine "kaputun altında" boru kullanımına güvenilebiliyor mu, biliyor musunuz? Ya da bash'ın gelecekteki farklı bir versiyonunda potansiyel olarak farklı olabilecek bir uygulama detayı mı? (Tabii ki, pratikte, bunu yapmanın en iyi yolu olduğunu anlıyorum ve bu nedenle farklı bir şekilde uygulanması pek mümkün değil.)
Eliah Kagan

1
Hayır, garanti edilmez, teorik olarak bir kabuk adlandırılmış bir fifo veya geçici dosya kullanabilir, ancak bunun için bir neden yoktur.
Random832

Tarihin genişlemesinden emin misiniz? Bunu engelleyebilecek tek karakter ` and '' ve grep ifadesinin etrafında tek tırnak kullanmanız gerekiyor.
muru

1
@muru Evet, genişletildi. Ben de fark etmedim, ama test ettiğimde öğrendim. !Orada alıntı değildir 'gibi -quotes '-quotes kendileri alıntı vardır. Komutun karmaşıklığı, etkisini yanlış tahmin etmeyi kolaylaştırır, ancak görünüşe göre genişlemelerin sırası nedeniyle ( !erken) , x=foo; echo "'$x'"(-> 'foo') gibi çalışmaya başlar . Dış "tırnak işaretlerinin kaldırılması tırnak !içine 'alınmasına ve geçmiş genişlemesinin önlenmesine neden olur , ancak cd dizin adında boşluk varsa başarısız olur.
Eliah Kagan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.