Як я можу записатись на попередній / наступний каталог братів та сестер?


10

У мене часто є такий макет каталогу проектів, як цей

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

Я, як правило, працюю в одному з componentкаталогів, тому що тут є файли. Після повернення до оболонки мені часто просто потрібно перейти до каталогу братів, особливо коли мені потрібно внести кілька змін, що не піддаються сценарію, для кожного компонента. У цих випадках мені навіть не байдуже, що саме я працюю над попереднім каталогом братів або наступним каталогом.

Чи можу я визначити команду prevчи nextце просто cdмене в попередній каталог або наступний каталог (за алфавітом чи будь-яким іншим)? Тому що друкувати cd ../com<TAB><Arrow keys>весь час старіє.

Відповіді:


8

Не використовуйте рішення командного рядка з іншої відповіді : це небезпечно¹ І неефективно .² Натомість, якщо ви використовуєте 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
}

¹ Він не обробляє всі можливі назви каталогів. Розбір lsрезультатів ніколи не є безпечним .

², cdмабуть, не потрібно бути надзвичайно ефективним, але 6 процесів трохи надмірно.


1
Я фактично використовую zsh, але якщо ви зміните перший тест у наступній функції for-loop, [[ -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 як прийняту, тому що моє запитання та випадок використання: "Я хочу перейти до наступного брата, і мені все одно, що це називається"; але це теж корисно і вишукано, тому є прихильність.
Естеїс

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
Команда, яку ви знайшли, має ряд проблем. Я відредагував це, щоб виправити найвиразніші з них: він розглядав ім'я каталогів як шаблону греп і дозволяв йому відповідати підрядковій лінії; і це було ім'я каталогу зазнають оболонки розкладання (слово розщеплення і підстановка) двічі (завжди використовувати подвійні лапки змінних і підстановки команд: "$foo", "$(foo)"). Крім того, розбір результатів роботи lsнедостовірний , він може не працювати з іменами файлів, що містять недруковані символи.
Жил "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.