Как я могу перейти к предыдущему / следующему каталогу?

10

У меня часто бывает макет директории проекта

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

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

Могу ли я определить команду, prevили nextона просто переведет cdменя в предыдущий каталог или следующий каталог (по алфавиту или как угодно)? Потому что печатать cd ../com<TAB><Arrow keys>все время становится немного старым.

Esteis
источник

Ответы:

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
}

Handle Он не обрабатывает все возможные имена каталогов. Разбор lsвывода никогда не бывает безопасным .

², cdвероятно, не должно быть ужасно эффективным, но 6 процессов немного чрезмерно.

jw013
источник
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
kitekat75
источник
Очень хорошо. Я сохраняю ответ jw013 как принятый, потому что мой вопрос и вариант использования были «Я хочу перейти к следующему брату, и мне все равно, как это называется»; но это тоже полезно и изящно, так что воздержитесь.
Esteis
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
Esteis
источник
2
Команда, которую вы нашли, имеет ряд проблем. Я отредактировал его, чтобы исправить самые вопиющие: он рассматривал имя каталога как шаблон grep и позволял ему соответствовать подстроке; и это было имя каталога претерпевают оболочки разложение (слово расщепления и подстановка) дважды (всегда использовать двойные кавычки переменных и подстановки команд: "$foo", "$(foo)"). Кроме того, синтаксический анализ вывода lsненадежен , он может не работать с именами файлов, содержащими непечатаемые символы.
Жиль "ТАК - перестать быть злым"