4

関数を記述したい一般的な使用例があります。ファイルに関連するディレクトリにcdしたいことがよくあります。

私の現在のワークフローは次のようになります。

$ gem which rspec/core | xargs echo -n | pbcopy
$ cd *paste and delete end until direcory looks right*

注:gem which rspec/core「/ Users / joshcheek / .rvm / gems / ruby​​-1.9.3-p125 / gems / rspec-core-2.10.0 / lib / rspec/core.rb」のように出力されます

私はそれをこのように見せたいです:

$ gem which rspec/core | 2dir 3

これにより、「/ Users / joshcheek / .rvm / gems / ruby​​-1.9.3-p125 / gems / rspec-core-2.10.0」に移動します(引数「3」を渡すと、「lib /rspec/」を削除するように指示されます。最後からcore.rb")

これは私がこれまでに得た中で最高です:

2dir() {
  read dir
  for i in $(seq 1 $1)
    do
      dir="${dir%/*}"
  done
  cd "$dir"
}

しかし、cdは関数のディレクトリを変更しますが、私のものではありません。エイリアスと交換しようとしましたが、無名関数を作成する方法や引数を渡す方法がわかりません。

4

5 に答える 5

9

私は使用します:

2dir()
{
    name=${2:?'Usage: 2dir count path'}
    count=$1
    while [[ $count -gt 0 ]]; do name=$(dirname "$name"); ((count--)); done
    cd "$name"
}

そしてそれを次のように使用します:

2dir 3 $(gem which rspec/core)

これは、パイプラインが機能しない場合に機能します。パイプ内プロセスはそのcd(サブ)シェルに影響しますが、親プロセスの現在のディレクトリには影響しません。この機能を動作させることができます。

また、必要に応じてdir="${dir%/*}"myの代わりにyourを使用できますdirname。ただし、10を指定すると、現在のディレクトリ(または、相対パス名と絶対パス名のどちらを指定したかによってはルートディレクトリ)ではなく、ホームディレクトリに移動します。コンポーネントが5つしかない場合。

于 2012-05-16T15:18:47.317 に答える
2

これは、使用を少し合理化するための@Jonathan Lefflerの提案の変形です。これにより、count引数がオプションになり$( )、コマンドを回避する必要がなくなります。

2dir() {
# If first arg is a number, use it as a trim count; otherwise assume 2
if [[ "$1" =~ ^[0-9]+$ ]]; then
    count="$1"
    shift
else
    count=2
fi

if [[ $# -lt 1 ]]; then  # Make sure a command was specified
    echo "Usage: 2dir [count] command [commandargs ...]" >&2
    return 1
fi

name="$("$@")"  # Execute the remaining args as a command to get the target directory
while [[ $count -gt 0 ]]; do name=$(dirname "$name"); ((count--)); done
cd "$name"
}

使用例:

2dir 3 gem which rspec/core
2dir gem which rspec/core
于 2012-05-16T18:09:57.137 に答える
1

このコマンド gem which rspec/core | 2dir 3 は、シェル用語では「パイプライン」と呼ばれます。パイプラインの各コマンドは、個別のプロセスとして実行されます。パイプライン内のコマンドの1つがシェル関数である場合、それは現在の(対話型)シェルプロセスによって実行される可能性があります。しかし、それは保証されておらず、あなたの場合、これは起こっていません。

問題を解決するには、関数がインタラクティブシェルで評価されていることを確認する必要があります。関数を修正してから、別の方法で使用する必要があります。更新された関数は次のとおりです。

2dir() {
  declare -ir snip="$1"
  declare dir="$2"
  for i in $(seq 1 "$snip"); do
      dir="${dir%/*}"
  done
  cd "$dir"
}

次のように使用します。

$ 2dir 3 "$(gem which rspec/core)"
于 2012-05-16T15:21:38.850 に答える
0

シェルスクリプトは、対話型シェルの作業ディレクトリを変更できません。ディレクトリを変更しようとしているシェルで実行されるため、エイリアスのみがそれを実行できます。

言い換えると:

シェルを実行しているLinuxプロセスがあり、ユーザーからのコマンドを受け入れます。作業ディレクトリがあります。シェルスクリプトを実行するように指示すると、最初のディレクトリから切断された、独立した作業ディレクトリを持つまったく新しいプロセスが作成されます。

于 2012-05-16T15:16:59.970 に答える
0

Jonathan Lefflerの回答に基づいていますが、ループはありません。

2dir () {
    local levels name=${2:?"Usage: $FUNCNAME count path"};
    printf -v levels '%*s' "$1" '';
    cd "/${name%${levels// //*}}"
}

厄介な点の1つは、先頭に2つのスラッシュが付いた完全に有効なディレクトリを生成することです(たとえば、関数の使用後に「// foo / bar / baz」を出力します)。echo "$PWD"

もう1つは、「半分賢すぎる」ということです。

編集:

ダブルスラッシュの問題を修正しました:

2dir () {
    local levels name=${2:?"Usage: $FUNCNAME count path"};
    printf -v levels '%*s' $1 '';
    name=/${name%${levels// //*}};
    cd "${name/\/\///}"
}
于 2012-05-17T03:51:21.890 に答える