Чи можете ви пояснити ці три речі в цьому баш-коді для мене?


10

У мене є functionв моєму .bashrcфайлі. Я знаю, що це робить, він підсилює X багато каталогівcd

Ось:

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
}

Але чи можете ви мені пояснити ці три речі?

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

Чому б просто не зробити так:

up()
{
    limit=$1

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

Використання:

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

Відповіді:


24
  1. d=$d/..додає /..до поточного вмісту dзмінної. dпочинається порожнім, потім перша ітерація робить це /.., друга /../..і т.д.

  2. sed 's/^\///'випадає перший /, так і /../..стає  ../..(це можна зробити за допомогою розширення параметра, d=${d#/}).

  3. d=.. має сенс лише в контексті його стану:

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

    Це гарантує, що, якщо dв цей момент порожній, ви переходите до батьківського каталогу. ( upбез аргументу, еквівалентного cd ...)

Цей підхід кращий, ніж ітеративний, cd ..оскільки він зберігає cd -- можливість повернутися до попереднього каталогу (з точки зору користувача) за один крок.

Функцію можна спростити:

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

Це передбачає, що ми хочемо просунутись хоча б на один рівень і додає n - 1 рівнів, тому нам не потрібно видаляти ведучі /або перевіряти наявність порожніх $d.

Використання Athena jot( athena-jotпакет у Debian):

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

(заснований на варіанті, запропонованому Гленном Джекманом ).


Так, $OLDPWDутрамбовувались. І на zsh з cdнабором використовувати dirstack, що теж.
муру

Чи є якась - то причина для призначення $1на limitзамість використання $1в циклі?
Нік Маттео

1
@kundor гарантує, що за замовчуванням дорівнює 0 (див. арифметику оболонки ). Ми могли використати ${1:-1}натомість, як у варіанті Глена.
Стівен Кітт

@kundor Також читабельність людини. Добре названа змінна говорить вам про те, що передбачається значення або мета першого аргументу, коли ви починаєте читати функцію, не спочатку знаючи, що функція виконує, або закінчити розуміння коду для її виведення.
mtraceur

2

Але чи можете ви мені пояснити ці три речі?

  1. d = $ d / ..

    Це об'єднує існуючий зміст вар dз /..і призначити його назад d.
    Кінцевий результат - зробити dповторний рядок, як /../../../...

  2. sed 's / ^ ///'

    Вилучіть провідну частину /з доданої рядки d(echo $ d) у коді, який ви опублікували.
    Напевно, краще написано, sed 's|^/||'щоб уникнути зворотної косої риски.

    Альтернативою (швидшою та простішою) є написання d=${d#/}.

  3. d = ..

    Призначте рядок ..до var d.
    Це має сенс лише як спосіб гарантувати наявність dпринаймні одного .. випадку, якщо тестові if [ -z "$d" ]; thenсигнали про те, що var dпорожній. І це може статися лише тому, що команда sed видаляє один символ d.
    Якщо немає необхідності видаляти символ з d, немає потреби sedабо if.


Код у вашому запитанні завжди буде рухатись принаймні на один dir.

Краще

  • local dдостатньо, щоб переконатися, що змінна порожня, нічого іншого не потрібно.
    Однак місцевий твір працює лише в деяких снарядах, таких як удар або тире. Зокрема, команда ksh(as yash) не має localкоманди. Більш портативне рішення:

    [ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
  • for((Синтаксис не є стерпним. Краще використовувати щось на кшталт:

    while [ "$((i+=1))" -lt "$limit" ]; do
  • Міцний.
    Якщо значення, задані для першого аргументу функції, можуть бути негативними або текстовими, функція повинна бути надійною для обробки цих значень.
    По-перше, давайте обмежувати значення лише числами (я буду використовувати cдля count):

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

    А потім обмежте значення підрахунку лише позитивними значеннями:

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

Ця функція з радістю прийме 0 або будь-який текст (без помилок):

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

Видаліть, echo \коли ви перевірили функцію.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.