Можете ли вы объяснить эти три вещи в этом коде 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 \когда вы проверили функцию.

Исаак
источник