Wie kann ich in das vorherige / nächste Geschwisterverzeichnis wechseln?

10

Ich habe oft ein solches Projektverzeichnislayout

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

Normalerweise arbeite ich in einem der componentVerzeichnisse, da sich dort die Dateien befinden. Wenn ich dann zur Shell zurückkehre, muss ich oft einfach in ein Geschwisterverzeichnis wechseln, insbesondere wenn ich an jeder Komponente einige nicht skriptfähige Änderungen vornehmen muss. In diesen Fällen ist es mir egal, an welchem ​​vorherigen Geschwisterverzeichnis ich arbeiten werde oder an welchem ​​nächsten Geschwisterverzeichnis ich arbeiten werde.

Kann ich einen Befehl definieren prevoder nextdas bringt cdmich einfach in das vorherige oder nächste Verzeichnis (nach Alphabet oder was auch immer)? Weil das ständige Tippen cd ../com<TAB><Arrow keys>etwas alt wird.

Esteis
quelle

Antworten:

8

Verwenden Sie nicht die Commandlinefu-Lösung aus der anderen Antwort : Sie ist unsicher¹ UND ineffizient.² Verwenden Sie stattdessen basheinfach die folgenden Funktionen , wenn Sie sie verwenden. Um sie dauerhaft zu machen, legen Sie sie in Ihre .bashrc. Beachten Sie, dass ich Glob Order verwende, weil es integriert und einfach ist. Typischerweise glob Reihenfolge ist in den meisten Gegenden alphabetisch though. Sie erhalten eine Fehlermeldung, wenn kein nächstes oder vorheriges Verzeichnis vorhanden ist. Insbesondere werden Sie den Fehler sehen , wenn Sie versuchen , nextoder prevwährend im Stammverzeichnis /.

## 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
}

¹ Es werden nicht alle möglichen Verzeichnisnamen verarbeitet. Das Parsen der lsAusgabe ist niemals sicher .

² muss cdwahrscheinlich nicht besonders effizient sein, aber 6 Prozesse sind etwas übertrieben.

jw013
quelle
1
Eigentlich benutze ich zsh, aber wenn Sie den ersten Test in der for-Schleife der nächsten Funktion in ändern, funktioniert [[ -n $foundcwd ]]Ihre Antwort unter bash und zsh gleich gut. Sehr schön, und danke, dass Sie dies geschrieben haben.
Esteis
4

Mit der folgenden Funktion können Sie in Geschwisterverzeichnisse wechseln (Bash-Funktion).

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
}

Ein Anwendungsbeispiel:

$ 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
kitekat75
quelle
Sehr schön. Ich behalte die Antwort von jw013 als die akzeptierte bei, da meine Frage und mein Anwendungsfall lauteten: "Ich möchte zum nächsten Geschwister wechseln, und es ist mir egal, wie es heißt." Aber das ist auch nützlich und geschickt, also stimmen Sie ab.
Esteis
2

Ich habe einen Tipp bei commandlinefu.com gefunden . Ich reposte es hier, um es besser auffindbar zu machen, mit einer Erklärung und einem nextBefehl, während ich dabei bin.

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)"'

Die Magie befindet sich im Block $ (...). Es leitet einige Befehle wie folgt ineinander:

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
Esteis
quelle
2
Der gefundene Befehl weist eine Reihe von Problemen auf. Ich habe es bearbeitet, um die ungeheuerlichsten zu korrigieren: Es behandelte den Verzeichnisnamen als grep-Muster und erlaubte ihm, mit einem Teilstring übereinzustimmen. und es hatte die Verzeichnisnamen Shell Erweiterung (Wort Spaltung und Globbing) zweimal (immer doppelte Anführungszeichen um variable und Befehlsersetzungen: laufen "$foo", "$(foo)"). Darüber hinaus ist das Parsen der Ausgabe von lsunzuverlässig und kann bei Dateinamen mit nicht druckbaren Zeichen fehlschlagen.
Gilles 'SO - hör auf böse zu sein'