Você pode explicar essas três coisas neste código de bash para mim?

10

Eu tenho um functionno meu .bashrcarquivo. Eu sei o que ele faz, intensifica X muitos diretórios comcd

Aqui está:

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
}

Mas você pode explicar essas três coisas para mim?

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

Por que não fazer assim:

up()
{
    limit=$1

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

Uso:

<<<>>>~$ up 3
<<<>>>/$
alguma coisa alguma coisa
fonte

Respostas:

24
  1. d=$d/..adiciona /..ao conteúdo atual da dvariável. dcomeça vazio, então a primeira iteração a faz /.., a segunda /../..etc.

  2. sed 's/^\///'cai o primeiro /, então /../..fica  ../..(isso pode ser feito usando uma expansão de parâmetro d=${d#/}).

  3. d=.. só faz sentido no contexto de sua condição:

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

    Isso garante que, se destiver vazio nesse momento, você vá para o diretório pai. ( upsem argumento é equivalente a cd ...)

Essa abordagem é melhor do que iterativa cd ..porque preserva cd -- a capacidade de retornar ao diretório anterior (da perspectiva do usuário) em uma etapa.

A função pode ser simplificada:

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

Isso pressupõe que queremos subir pelo menos um nível e adiciona níveis n-1 , para que não seja necessário remover o líder /ou verificar se há um vazio $d.

Usando Athena jot(o athena-jotpacote no Debian):

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

(com base em uma variante sugerida por glenn jackman ).

Stephen Kitt
fonte
Sim, $OLDPWDser pisoteado veio à mente. E no zsh com cdset para usar o dirstack, isso também.
muru 18/10/19
Existe algum motivo para atribuir $1ao limitinvés de apenas usar $1no loop?
Nick Matteo
1
@kundor garante que o padrão é 0 (veja aritmética do shell ). Em ${1:-1}vez disso, poderíamos usar , como na variante de Glenn.
Stephen Kitt
@ kundor Também legibilidade humana. Uma variável bem nomeada informa qual é o significado ou o objetivo pretendido do primeiro argumento quando você começa a ler a função, sem precisar primeiro saber o que a função faz ou terminar de entender o código para deduzi-la.
Mtraceur 18/10/19
2

Mas você pode explicar essas três coisas para mim?

  1. d = $ d / ..

    Este concatena o conteúdo presente do var dcom /..e atribuí-lo de volta para d.
    O resultado final é criar duma sequência repetida como /../../../...

  2. / s / ^ /// '

    Remova o líder /da sequência fornecida d(eco $ d) no código que você postou.
    Provavelmente melhor escrito sed 's|^/||'para evitar a barra invertida.

    Uma alternativa (mais rápida e simples) é escrever d=${d#/}.

  3. d = ..

    Atribua a string ..à var d.
    Isso só faz sentido como uma maneira de garantir que dhaja pelo menos um .. caso o teste if [ -z "$d" ]; thenindique que o var destá vazio. E isso só pode acontecer porque o comando sed está removendo um caractere d.
    Se não houver necessidade de remover o caractere de d, não haverá necessidade de sedou if.


O código na sua pergunta sempre subirá pelo menos um diretório.

Melhor

  • local dé suficiente para garantir que a variável esteja vazia, nada mais é necessário.
    No entanto, o local funciona apenas em alguns shells como bash ou dash. Em específico, ksh(as yash) não possui um localcomando. Uma solução mais portátil é:

    [ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
  • A for((sintaxe não é portátil. Melhor usar algo como:

    while [ "$((i+=1))" -lt "$limit" ]; do
  • Robusto.
    Se os valores dados ao primeiro argumento da função puderem ser negativos ou texto, a função deve ser robusta para processar esses valores.
    Primeiro, vamos limitar os valores a apenas números (usarei cpara count):

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

    E, em seguida, limite o valor da contagem apenas a valores positivos:

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

Esta função aceita 0 ou qualquer texto (sem erros):

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

Remova o echo \quando você tiver testado a função.

Isaac
fonte