CDのパスとしてgrep出力を使用する方法


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 '/.*')"

これは、/後に続く*任意の文字(.)の0個以上()に一致します。

ディレクトリ名に水平方向の空白(スペースやタブなし)が含まれておらず、行末に表示されていることがわかっている場合は、次を使用できます。

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

ここでは、Perl正規表現-P)を使用ました。これは、\h略語(for [:blank:])を使用すると、同等の拡張正規表現(-E)よりも入力や読み取りが簡単になるためです。これは、スペースまたはタブ()ではない()+文字のクラス()内の任意の文字の1つ以上()と一致します。[ ]^\h

あなたがトンを知っていれば、彼は、ディレクトリ名のすぐに先行されるin水平方向の空白に囲まれた(すなわち、ブランクで左右両方に埋め)、およびこと、これが唯一のような発生であるinライン上の、あなたが使用することができます。

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

これは、ゼロ幅のポジティブ後読みアサーション(\K)を使用して.+、スペースまたはタブ(\h)の後に表示される1つ以上の文字()in、および別の1つ以上のスペースまたはタブ(\h+)と一致しますが、実際にinは、空白スペースは含まれません。試合でそれを囲む。ルックアラウンドアサーションは、Perl正規表現の機能です。

パターンも機能しますが、存在する数に関係なく、前に1つの空白を探すだけで済みます。対照的に、の後のすべての空白を一致させる必要があります。一致ない場合、空白は破棄されず、ディレクトリ名の一部として一致します。\h+in\h+\K.+inin\K

ディレクトリ名の直前に行が最後に出現し、inその後に水平空白が続くことがわかっている場合、次のように使用できます。

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

そこでは、ゼロ幅ポジティブ後読みアサーション自体にゼロ幅ネガティブ先読みアサーションが含まれています((?! ))。

!難しいことするように表示されてエスケープするエレガント。渡される前にシェルの履歴の展開がトリガーされないようにするために使用した方法grepset +H、コマンドを実行する前に履歴の展開を一時的に無効にし(set -H)、後で再度有効にする()ことです。これをスクリプトで使用していて、スクリプトにが含まれset -Hていない場合は、シェルがインタラクティブに実行されたときにのみ履歴の拡張が自動的に有効になるため、これを行う必要はありません。

最後に、これらのいずれもheemaylの回答も実際にgrepto cdの出力をpipパイプ処理していないことに注意してください(出力はまだにパイプ処理されていますgrep)。パイプではなく、このジョブに適したツールはコマンド置換です。


もちろん、技術的な情報を入手したい場合、シェルは内部でパイプを使用してコマンド出力を読み取ります。
Random832 2015

@ Random832良い点-これを考慮して少し編集しました。ところで、コマンド置換で「ボンネットの下」のパイプの使用が信頼できるかどうか知っていますか?それとも、bashの将来の別のバージョンでは異なる方法で実行される可能性がある実装の詳細ですか?(もちろん、実際には、それが最良の方法であることを理解しています。したがって、別の方法で実装されることはほとんどありません。)
Eliah Kagan

1
いいえ、それは保証されていません。理論的には、シェルは名前付きのfifoまたは一時ファイルを使用できますが、理由はありません。
Random832 2015

歴史の拡大について確信がありますか?それをブロックできるのは` and '` だけで、grep式を一重引用符で囲む必要があります。
muru、2015

1
@muru はい、拡張されています。気づかなかったのですが、テストしてみたらわかりました。!そこに引用されていない'として、-quotes '-quotes自体が引用されています。コマンドの複雑さにより、その効果を誤って予測しやすくなりますが、展開の順序が原因である(!早い)ため、最終的にx=foo; echo "'$x'"(-> 'foo')のように機能します。外側の"-quotesを削除すると、-quotedが発生!して'履歴が拡張されなくなりますcd が、ディレクトリの名前に空白が含まれていると失敗します。
Eliah Kagan、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.