Bisakah Anda menjelaskan tiga hal ini dalam kode bash ini untuk saya?

10

Saya punya functiondi .bashrcfile saya . Saya tahu apa fungsinya, ia meningkatkan X banyak direktoricd

Ini dia:

up()
{
    local d=""
    limit=$1
    for ((i=1 ; i <= limit ; i++))
      do
        d=$d/..
      done
    d=$(echo $d | sed 's/^\///')
    if [ -z "$d" ]; then
      d=..
    fi
    cd $d
}

Tetapi bisakah Anda menjelaskan tiga hal ini untuk saya?

  1. d=$d/..
  2. sed 's/^\///'
  3. d=..

Mengapa tidak melakukan seperti ini:

up()
{
    limit=$1

    for ((i=1 ; i <= limit ; i++))
    do
        cd ..
    done
}

Pemakaian:

<<<>>>~$ up 3
<<<>>>/$
sesuatu Sesuatu
sumber

Jawaban:

24
  1. d=$d/..menambah /..isi dvariabel saat ini. ddimulai dengan kosong, kemudian iterasi pertama membuatnya /.., yang kedua /../..dll

  2. sed 's/^\///'menjatuhkan yang pertama /, jadi /../..menjadi  ../..(ini bisa dilakukan dengan menggunakan ekspansi parameter, d=${d#/}).

  3. d=.. hanya masuk akal dalam konteks kondisinya:

    if [ -z "$d" ]; then
      d=..
    fi

    Ini memastikan bahwa, jika dkosong pada titik ini, Anda pergi ke direktori induk. ( uptanpa argumen setara dengan cd ...)

Pendekatan ini lebih baik daripada berulang cd ..karena mempertahankan cd -- kemampuan untuk kembali ke direktori sebelumnya (dari perspektif pengguna) dalam satu langkah.

Fungsi ini dapat disederhanakan:

up() {
  local d=..
  for ((i = 1; i < ${1:-1}; i++)); do d=$d/..; done
  cd $d
}

Ini mengasumsikan kita ingin naik setidaknya satu level, dan menambahkan level n - 1 , jadi kita tidak perlu menghapus yang memimpin /atau memeriksa yang kosong $d.

Menggunakan Athena jot( athena-jotpaket dalam bahasa Debian):

up() { cd $(jot -b .. -s / "${1:-1}"); }

(berdasarkan varian yang disarankan oleh glenn jackman ).

Stephen Kitt
sumber
Yap, $OLDPWDdiinjak-injak datang ke pikiran. Dan pada zsh dengan cdset untuk menggunakan dirstack, itu juga.
muru
Apakah ada beberapa alasan untuk menugaskan $1untuk limitbukan hanya menggunakan $1dalam lingkaran?
Nick Matteo
1
@kundor memastikan default adalah 0 (lihat aritmatika shell ). Kita bisa menggunakan ${1:-1}sebagai gantinya, seperti pada varian glenn.
Stephen Kitt
@kundor Juga keterbacaan manusia. Variabel yang diberi nama dengan baik memberi tahu Anda apa maksud atau tujuan dari argumen pertama adalah ketika Anda mulai membaca fungsi, tanpa harus terlebih dahulu tahu apa fungsi itu atau selesai memahami kode untuk menyimpulkannya.
mtraceur
2

Tetapi bisakah Anda menjelaskan tiga hal ini untuk saya?

  1. d = $ d / ..

    Ini menggabungkan isi var ddengan /..dan memberikannya kembali d.
    Hasil akhirnya adalah membuat dstring yang berulang seperti /../../../...

  2. sed 's / ^ ///'

    Hapus pemimpin /dari string yang disediakan, d(echo $ d) dalam kode yang Anda posting.
    Mungkin ditulis lebih baik sed 's|^/||'untuk menghindari backslash.

    Alternatif (lebih cepat dan lebih sederhana) adalah menulis d=${d#/}.

  3. d = ..

    Tetapkan string ..ke var d.
    Ini hanya masuk akal sebagai cara untuk memastikan bahwa dsetidaknya ada satu .. dalam kasus tes if [ -z "$d" ]; thenmenandakan bahwa var dkosong. Dan itu hanya dapat terjadi karena perintah sed menghapus satu karakter dari d.
    Jika tidak perlu menghapus karakter dari d, tidak perlu sedatau if.


Kode dalam pertanyaan Anda akan selalu naik setidaknya satu dir.

Lebih baik

  • local dsudah cukup untuk memastikan bahwa variabel kosong, tidak ada lagi yang diperlukan.
    Namun, lokal hanya berfungsi di beberapa shell seperti bash atau dash. Secara khusus, ksh(as yash) tidak memiliki localperintah. Solusi yang lebih portabel adalah:

    [ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
  • The for((sintaks tidak portabel. Lebih baik gunakan sesuatu seperti:

    while [ "$((i+=1))" -lt "$limit" ]; do
  • Kuat.
    Jika nilai yang diberikan ke argumen fungsi pertama bisa negatif atau teks, fungsi harus kuat untuk memproses nilai-nilai tersebut.
    Pertama, mari kita batasi nilai hanya untuk angka (saya akan gunakan cuntuk count):

    c=${1%%[!0-9]*}

    Dan kemudian batasi nilai hitungan hanya untuk nilai positif:

    let "c = (c>0)?c:0"

Fungsi ini akan dengan senang hati menerima 0 atau teks apa pun (tanpa kesalahan):

up()
{
    [ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
    c=${1%%[!0-9]*}
    c=$(((c>0)?c:0))
    while [ "$((i+=1))" -le "$c" ]; do d="$d../"; done
    echo \
        cd "${d%/}"         # Removing the trailing / is not really needed for cd
                            # but it is nice to know it could be done cleanly.
}

up 2
up 0
up asdf

Hapus echo \ketika Anda telah menguji fungsi.

Ishak
sumber