Come posso effettuare il cd nella directory dei fratelli precedente / successivo?


10

Ho spesso un layout di directory di progetto come questo

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

Di solito lavorerò in una delle componentdirectory, perché è lì che si trovano i file. Quando poi torno alla shell, spesso ho semplicemente bisogno di passare a una directory di pari livello, specialmente quando ho bisogno di apportare alcune modifiche non programmabili a ogni componente. In questi casi, non mi preoccuperò nemmeno di quale sia la precedente directory di pari livello su cui lavorerò o la prossima directory di pari livello.

Posso definire un comando prevo nextche semplicemente cdmi porterà nella directory precedente o nella directory successiva (in ordine alfabetico o altro)? Perché digitare cd ../com<TAB><Arrow keys>sempre diventa un po 'vecchio.

Risposte:


8

Non usare la soluzione commandlinefu dell'altra risposta : non è sicura¹ E inefficiente.² Se invece stai usando bash, usa solo le seguenti funzioni. Per renderli persistenti, inseriscili nel tuo .bashrc. Nota che uso glob order perché è integrato e facile. In genere, però, l'ordine globale è alfabetico nella maggior parte dei locali. Riceverai un messaggio di errore se non ci sono directory successive o precedenti da visitare. In particolare, si vedrà l'errore se si tenta di nexto prevmentre nella directory principale, /.

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

¹ Non gestisce tutti i possibili nomi di directory. L' lsoutput di analisi non è mai sicuro .

² cdprobabilmente non deve essere terribilmente efficiente, ma 6 processi sono un po 'eccessivi.


1
In realtà uso zsh, ma se cambi il primo test nel for-loop della funzione successiva in [[ -n $foundcwd ]]allora la tua risposta funziona ugualmente bene con bash e zsh. Molto bello, e grazie per averlo scritto.
Esteis,

4

La seguente funzione consente di passare alle directory dei fratelli (funzione 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
}

Un esempio di utilizzo:

$ 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

Molto bella. Sto mantenendo la risposta di jw013 come accettata, perché la mia domanda e il mio caso d'uso erano "Voglio passare al fratello successivo e non mi interessa come si chiama"; ma anche questo è utile e elegante, quindi hai un voto positivo.
Esteis,

2

Ho trovato un suggerimento su commandlinefu.com . Lo sto ripubblicando qui per renderlo più rintracciabile, con una spiegazione e un nextcomando aggiunti mentre ci sono.

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

La magia è nel blocco `$ (...). Inoltra alcuni comandi tra loro come segue:

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
Il comando che hai riscontrato presenta numerosi problemi. L'ho modificato per correggere quelli più eclatanti: trattava il nome della directory come un modello grep e gli permetteva di abbinare una sottostringa; e aveva il nome della directory subisce l'espansione della shell (parola scissione e globbing) due volte (usare sempre le virgolette intorno sostituzioni di variabili e di comando: "$foo", "$(foo)"). Inoltre, l' analisi dell'output di lsnon è affidabile , potrebbe non riuscire con nomi di file contenenti caratteri non stampabili.
Gilles 'SO- smetti di essere malvagio' il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.