Bạn có thể giải thích ba điều trong mã bash này cho tôi không?


10

Tôi có một functiontrong .bashrctập tin của tôi . Tôi biết những gì nó làm, nó bước lên X nhiều thư mục vớicd

Đây là:

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
}

Nhưng bạn có thể giải thích ba điều này từ nó cho tôi?

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

Tại sao không làm như thế này:

up()
{
    limit=$1

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

Sử dụng:

<<<>>>~$ up 3
<<<>>>/$

Câu trả lời:


24
  1. d=$d/..thêm /..vào nội dung hiện tại của dbiến. dbắt đầu trống rỗng, sau đó lần lặp đầu tiên làm cho nó /.., lần thứ hai, /../..v.v.

  2. sed 's/^\///'bỏ cái đầu tiên /, vì vậy /../..trở thành  ../..(điều này có thể được thực hiện bằng cách sử dụng mở rộng tham số d=${d#/}).

  3. d=.. chỉ có ý nghĩa trong bối cảnh của điều kiện của nó:

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

    Điều này đảm bảo rằng, nếu dtrống vào thời điểm này, bạn vào thư mục cha. ( upkhông có đối số tương đương với cd ...)

Cách tiếp cận này tốt hơn lặp đi lặp lại cd ..vì nó bảo tồn cd -- khả năng quay lại thư mục trước đó (từ phối cảnh của người dùng) trong một bước.

Các chức năng có thể được đơn giản hóa:

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

Điều này giả định rằng chúng tôi muốn tăng lên ít nhất một cấp độ và thêm n cấp 1 , vì vậy chúng tôi không cần xóa vị trí dẫn đầu /hoặc kiểm tra trống $d.

Sử dụng Athena jot( athena-jotgói trong Debian):

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

(dựa trên một biến thể được đề xuất bởi glenn jackman ).


Đúng, $OLDPWDbị chà đạp lên tâm trí. Và trên zsh với cdthiết lập để sử dụng dirstack, điều đó cũng vậy.
muru

Có một số lý do để gán $1cho limitthay vì chỉ sử dụng $1trong vòng lặp?
Nick Matteo

1
@kundor nó đảm bảo mặc định là 0 (xem số học shell ). Chúng ta có thể sử dụng ${1:-1}thay thế, như trong biến thể của glenn.
Stephen Kitt

@kundor Cũng dễ đọc của con người. Một biến có tên tốt cho bạn biết ý nghĩa hoặc mục đích dự định của đối số đầu tiên là gì khi bạn bắt đầu đọc hàm, mà không cần phải biết hàm này làm gì hoặc hoàn thành việc hiểu mã để suy ra nó.
mtraceur

2

Nhưng bạn có thể giải thích ba điều này từ nó cho tôi?

  1. d = $ d / ..

    Điều này nối các nội dung hiện tại của var dvới /..và gán lại cho d.
    Kết quả cuối cùng là tạo ra dmột chuỗi lặp lại như thế nào /../../../...

  2. sed 's / ^ ///'

    Xóa phần dẫn /ra khỏi chuỗi được cung cấp, d(echo $ d) trong mã bạn đã đăng.
    Có lẽ tốt hơn bằng văn bản là sed 's|^/||'để tránh dấu gạch chéo ngược.

    Một cách khác (nhanh hơn và đơn giản hơn) là viết d=${d#/}.

  3. d = ..

    Gán chuỗi ..cho var d.
    Điều này chỉ có ý nghĩa như một cách để đảm bảo dcó ít nhất một .. trong trường hợp các if [ -z "$d" ]; thentín hiệu kiểm tra rằng var dtrống. Và điều đó chỉ có thể xảy ra vì lệnh sed đang loại bỏ một ký tự d.
    Nếu không cần xóa ký tự khỏi d, thì không cần sedhoặc if.


Mã trong câu hỏi của bạn sẽ luôn di chuyển lên ít nhất một thư mục.

Tốt hơn

  • local dlà đủ để đảm bảo rằng biến đó trống, không có gì khác là cần thiết.
    Tuy nhiên, công trình địa phương chỉ trong một số shell như bash hoặc dash. Cụ thể, ksh(như yash) không có locallệnh. Một giải pháp di động hơn là:

    [ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
  • Các for((cú pháp không phải là cầm tay. Tốt hơn nên sử dụng một cái gì đó như:

    while [ "$((i+=1))" -lt "$limit" ]; do
  • Mạnh mẽ.
    Nếu các giá trị được cung cấp cho hàm đối số đầu tiên có thể là âm hoặc văn bản, hàm sẽ mạnh mẽ để xử lý các giá trị đó.
    Thứ nhất, cho phép hạn chế các giá trị đến các số chỉ (Tôi sẽ sử dụng ccho count):

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

    Và sau đó giới hạn giá trị đếm chỉ ở các giá trị dương:

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

Hàm này sẽ nhanh chóng chấp nhận 0 hoặc bất kỳ văn bản nào (không có lỗi):

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

Hủy bỏ echo \khi bạn đã kiểm tra chức năng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.