どうすれば前/次の兄弟ディレクトリにcdできますか?


10

私はよくこのようなプロジェクトディレクトリのレイアウトを持っています

project
`-- component-a
|   `-- files...
`-- component-b
|   `-- files...
`-- component-c
    `-- files...

componentファイルがある場所だから、私は通常、ディレクトリの1つで作業します。その後シェルに戻ると、特にすべてのコンポーネントにスクリプトを使用できない変更をいくつか加える必要がある場合は、兄弟ディレクトリに移動する必要があることがよくあります。それらの場合、私は前の兄弟ディレクトリーが何であるか、または次の兄弟ディレクトリーが何であるかさえ気にしません。

私は、コマンドを定義することができるprevか、nextそれは単に意志cd私(アルファベットまたは何によって)前のディレクトリ、または次のディレクトリに?cd ../com<TAB><Arrow keys>いつもタイピングは少し古くなっているからです。

回答:


8

他の回答の commandlinefuソリューションを使用しないでください。安全ではなく、非効率的です²。代わりに、をbash使用している場合は、次の関数を使用してください。それらを永続化するには、それらをに入れます.bashrc。組み込みで簡単なので、グロブ順を使用していることに注意してください。通常、グロブの順序ほとんどのロケールでアルファベット順です。移動する次または前のディレクトリがない場合は、エラーメッセージが表示されます。特に、ルートディレクトリに移動しようとしたとき、nextまたはprevルートディレクトリに/いるときにエラーが表示されます。

## bash and zsh only!
# functions to cd to the next or previous sibling directory, in glob order

prev () {
    # default to current directory if no previous
    local prevdir="./"
    local cwd=${PWD##*/}
    if [[ -z $cwd ]]; then
        # $PWD must be /
        echo 'No previous directory.' >&2
        return 1
    fi
    for x in ../*/; do
        if [[ ${x#../} == ${cwd}/ ]]; then
            # found cwd
            if [[ $prevdir == ./ ]]; then
                echo 'No previous directory.' >&2
                return 1
            fi
            cd "$prevdir"
            return
        fi
        if [[ -d $x ]]; then
            prevdir=$x
        fi
    done
    # Should never get here.
    echo 'Directory not changed.' >&2
    return 1
}

next () {
    local foundcwd=
    local cwd=${PWD##*/}
    if [[ -z $cwd ]]; then
        # $PWD must be /
        echo 'No next directory.' >&2
        return 1
    fi
    for x in ../*/; do
        if [[ -n $foundcwd ]]; then
            if [[ -d $x ]]; then
                cd "$x"
                return
            fi
        elif [[ ${x#../} == ${cwd}/ ]]; then
            foundcwd=1
        fi
    done
    echo 'No next directory.' >&2
    return 1
}

possibleすべての可能なディレクトリ名を処理するわけではありません。 出力の解析lsは決して安全ではありません

² cdおそらくそれほど効率的である必要はありませんが、6つのプロセスは少し過剰です。


1
私は実際にはzshを使用していますが、次の関数のforループの最初のテストを次のように変更すると、[[ -n $foundcwd ]]bashとzshのどちらでも問題なく動作します。とても素敵で、これを書いてくれてありがとう。
Esteis

4

次の関数は兄弟ディレクトリへの変更を許可します(bash関数)

function sib() {
    ## sib  search sibling directories 
    ##   prompt for choice (when two or more directories are found, current dir is removed from choices) 
    ##   change to directory after selection 
    local substr=$1
    local curdir=$(pwd)
    local choices=$(find .. -maxdepth 1 -type d -name "*${substr}*" | grep -vE '^..$' | sed -e 's:../::' | grep -vE "^${curdir##*/}$" | sort)
    if [ -z "$choices" ]; then
        echo "Sibling directory not found!"
        return
    fi
    local count=$(echo "$choices" | wc -l)
    if [[ $count -eq 1 ]]; then
        cd ../$choices
        return 
    fi
    select dir in $choices; do
        if [ -n "$dir" ]; then
            cd ../$dir
        fi
        break
    done
}

使用例:

$ tree
  .
  ├── component-aaa-01
  ├── component-aaa-02
  ├── component-bbb-01
  ├── component-bbb-02
  ├── component-ccc-01
  ├── component-ccc-02
  └── component-ccc-03
  7 directories, 0 files
  $ cd component-aaa-01/
  $ sib bbb-01
  $ pwd
  component-bbb-01
  $ sib bbb
  $ pwd
  component-bbb-02
  $ sib ccc
  1) component-ccc-01
  2) component-ccc-02
  3) component-ccc-03
  #? 3
  $ pwd
  component-ccc-03
  $ sib 01
  1) component-aaa-01
  2) component-bbb-01
  3) component-ccc-01
  #? 2
  $ pwd
  component-bbb-01

非常に素晴らしい。私の質問とユースケースは「次の兄弟に移動したいのですが、それが何と呼ばれるかは気にしません」だったので、私はjw013の回答を受け入れられたものとして保持しています。しかし、これも便利であり、気の利いたものなので、賛成投票をしてください。
Esteis 2014

2

commandlinefu.comでヒントが見つかりました。見つけやすくするために、ここに再投稿しています。説明とnextコマンドが追加されています。

alias prev='cd ../"$(ls -F .. | grep '/' | grep -B1 -xF "${PWD##*/}/" | head -n 1)"'
alias next='cd ../"$(ls -F .. | grep '/' | grep -A1 -xF "${PWD##*/}/" | tail -n 1)"'

魔法は `$(...)ブロックにあります。次のように、いくつかのコマンドを相互にパイプします。

ls -F .. |   # list items in parent dir; `-F` requests filetype indicators
grep '/' |   # select the directories (written as  `mydir/`)
grep -B1 -xF "${PWD##*/}/" |   # search for the name of the current directory in the output;
                               # print it and the line preceding it
head -n 1    # the first of those two lines contains the name of the previous sibling

2
見つけたコマンドにはいくつかの問題があります。最も悪質なものを修正するために編集しました。ディレクトリ名をgrepパターンとして扱い、部分文字列との一致を許可していました。また、ディレクトリ名にシェル拡張(単語分割とグロビング)を2回実行しました(常に変数とコマンドの置換を二重引用符で囲みます:"$foo""$(foo)")。さらに、の出力の解析lsは信頼できません。印刷できない文字を含むファイル名で失敗する可能性があります。
Gilles「SO-悪をやめる」
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.