Bagaimana saya bisa melakukan cd ke direktori saudara sebelumnya / selanjutnya?

10

Saya sering memiliki tata letak direktori proyek seperti ini

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

Saya biasanya akan bekerja di salah satu componentdirektori, karena di situlah file berada. Ketika saya kemudian kembali ke shell, saya akan sering hanya perlu pindah ke direktori saudara, terutama ketika saya perlu membuat beberapa perubahan non-skrip untuk setiap komponen. Dalam kasus itu, saya bahkan tidak akan peduli apa direktori saudara sebelumnya yang akan saya kerjakan, atau direktori saudara berikutnya.

Bisakah saya mendefinisikan suatu perintah prevatau nextitu hanya akan cdsaya ke direktori sebelumnya, atau direktori berikutnya (dengan alfabet atau apa pun)? Karena mengetik cd ../com<TAB><Arrow keys>sepanjang waktu semakin lama.

Esteis
sumber

Jawaban:

8

Jangan gunakan solusi commandlinefu dari jawaban lain : tidak aman¹ DAN tidak efisien.² Sebaliknya, jika Anda menggunakan bash, gunakan saja fungsi-fungsi berikut. Untuk membuat mereka gigih, masukkan mereka ke dalam .bashrc. Perhatikan bahwa saya menggunakan glob order karena built-in dan mudah. Biasanya urutan gumpal adalah abjad di kebanyakan lokal sekalipun. Anda akan mendapatkan pesan kesalahan jika tidak ada direktori berikutnya atau sebelumnya untuk pergi. Secara khusus, Anda akan melihat kesalahan jika Anda mencoba nextatau prevketika berada di direktori root /,.

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

¹ Itu tidak menangani semua nama direktori yang mungkin. Parsing lsoutput tidak pernah aman .

² cdmungkin tidak perlu sangat efisien, tetapi 6 proses agak berlebihan.

jw013
sumber
1
Saya menggunakan zsh, sebenarnya, tetapi jika Anda mengubah tes pertama di for-loop fungsi berikutnya untuk [[ -n $foundcwd ]]kemudian jawaban Anda bekerja di bawah bash dan zsh sama baiknya. Sangat bagus, dan terima kasih telah menulis ini.
Esteis
4

Fungsi berikut mengizinkan untuk mengubah ke direktori saudara (fungsi 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
}

Contoh penggunaan:

$ 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
sumber
Sangat bagus. Saya menjaga jawaban jw013 sebagai yang diterima, karena pertanyaan dan kasus penggunaan saya adalah 'Saya ingin pindah ke saudara berikutnya, dan saya tidak peduli apa namanya'; tapi ini berguna juga, dan bagus, jadi jangan pilih-pilih.
Esteis
2

Saya menemukan tip di commandlinefu.com . Saya memposting ulang di sini untuk membuatnya lebih mudah ditemukan, dengan penjelasan dan nextperintah ditambahkan saat saya melakukannya.

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

Keajaiban ada di blok `$ (...). Ini pipa beberapa perintah satu sama lain sebagai berikut:

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
sumber
2
Perintah yang Anda temukan memiliki sejumlah masalah. Saya telah mengeditnya untuk memperbaiki yang paling mengerikan: ia memperlakukan nama direktori sebagai pola grep dan memungkinkannya untuk mencocokkan substring; dan itu nama direktori menjalani ekspansi shell (kata membelah dan globbing) dua kali (selalu menggunakan tanda kutip ganda di sekitar variabel dan perintah substitusi: "$foo", "$(foo)"). Selain itu, parsing output lstidak dapat diandalkan , mungkin gagal dengan nama file yang mengandung karakter yang tidak patut.
Gilles 'SO- berhenti bersikap jahat'