Можете ли вы объяснить эти три вещи в этом коде Bash для меня?


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. д = $ д / ..

    Это объединяет текущее содержимое var dс /..и присваивает его обратно d.
    Конечным результатом является создание dповторяющейся строки, как /../../../...

  2. sed 's / ^ ///'

    Удалите начальную /строку из предоставленной строки d(echo $ d) в коде, который вы разместили
    Наверное, лучше написано, sed 's|^/||'чтобы избежать обратной косой черты.

    Альтернатива (быстрее и проще) - написать d=${d#/}.

  3. d = ..

    Назначьте строку ..в var d.
    Это имеет смысл только как способ обеспечить наличие dхотя бы одного .. в случае, если тестовые if [ -z "$d" ]; thenсигналы указывают на то, что переменная dпуста. И это может произойти только потому, что команда sed удаляет один символ из d.
    Если нет необходимости удалять символ из d, нет необходимости в sedили if.


Код в вашем вопросе всегда будет перемещаться вверх хотя бы на один каталог.

Лучше

  • local dдостаточно, чтобы убедиться, что переменная пуста, больше ничего не нужно.
    Однако локальный работает только в некоторых оболочках, таких как bash или dash. В частности, ksh(как yash) не имеет localкоманды. Более портативное решение:

    [ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
  • for((Синтаксис не является переносимым. Лучше использовать что-то вроде:

    while [ "$((i+=1))" -lt "$limit" ]; do
  • Robust.
    Если значения, данные первому аргументу функции, могут быть отрицательными или текстовыми, функция должна быть устойчивой для обработки этих значений.
    Во-первых, давайте ограничим значения только цифрами (я буду использовать 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.