Puoi spiegarmi queste tre cose in questo codice bash per me?


10

Ho un functionnel mio .bashrcfile. So cosa fa, aumenta di X molte directory concd

Ecco qui:

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
}

Ma puoi spiegarmi queste tre cose?

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

Perché non fare così:

up()
{
    limit=$1

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

Uso:

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

Risposte:


24
  1. d=$d/..aggiunge /..al contenuto corrente della dvariabile. dinizia vuoto, quindi la prima iterazione lo fa /.., la seconda /../..ecc.

  2. sed 's/^\///'elimina il primo /, quindi /../..diventa  ../..(questo può essere fatto usando un parametro di espansione d=${d#/}).

  3. d=.. ha senso solo nel contesto della sua condizione:

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

    Ciò garantisce che, se dè vuoto a questo punto, si passa alla directory principale. ( upsenza argomenti equivale a cd ...)

Questo approccio è migliore dell'iterativo cd ..perché preserva cd -: la possibilità di tornare alla directory precedente (dal punto di vista dell'utente) in un solo passaggio.

La funzione può essere semplificata:

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

Ciò presuppone che desideriamo salire di almeno un livello e aggiungere n - 1 livelli, quindi non è necessario rimuovere il comando iniziale /o verificare che sia vuoto $d.

Usando Athena jot(il athena-jotpacchetto in Debian):

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

(basato su una variante suggerita da Glenn Jackman ).


Sì, mi è $OLDPWDvenuto in mente di essere calpestato. E su zsh con cdset per usare anche il dirstack.
muru,

C'è qualche motivo per assegnare $1a limitinvece di utilizzare $1nel ciclo?
Nick Matteo,

1
@kundor assicura che il valore predefinito sia 0 (vedi l' aritmetica della shell ). Potremmo usare ${1:-1}invece, come nella variante di Glenn.
Stephen Kitt,

@kundor Anche la leggibilità umana. Una variabile ben definita ti dice qual è il significato o lo scopo previsto del primo argomento quando inizi a leggere la funzione, senza dover prima sapere cosa fa la funzione o finire di comprendere il codice per dedurla.
mtraceur,

2

Ma puoi spiegarmi queste tre cose?

  1. d = $ d / ..

    Questo concatena il contenuto attuale di var dcon /..e lo riassegna a d.
    Il risultato finale è creare duna stringa ripetuta come /../../../...

  2. sed 's / ^ ///'

    Rimuovi il lead /dalla stringa fornita, d(echo $ d) nel codice che hai pubblicato.
    Probabilmente meglio scritto sed 's|^/||'per evitare la contraccolpo.

    Un'alternativa (più veloce e più semplice) è scrivere d=${d#/}.

  3. d = ..

    Assegna la stringa ..al var d.
    Questo ha senso solo come un modo per assicurarsi che dabbia almeno uno .. nel caso in cui il test if [ -z "$d" ]; thensegnali che il var dè vuoto. E ciò può accadere solo perché il comando sed sta rimuovendo un personaggio da d.
    Se non è necessario rimuovere il carattere da d, non è necessario per sedo if.


Il codice nella tua domanda salirà sempre di almeno una directory.

Meglio

  • local dè sufficiente per assicurarsi che la variabile sia vuota, nient'altro è necessario.
    Tuttavia, local funziona solo in alcune shell come bash o dash. In particolare, ksh(as yash) non ha un localcomando. Una soluzione più portatile è:

    [ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
  • La for((sintassi non è portatile. Meglio usare qualcosa come:

    while [ "$((i+=1))" -lt "$limit" ]; do
  • Robusta.
    Se i valori forniti al primo argomento della funzione potrebbero essere negativi o di testo, la funzione dovrebbe essere solida per elaborare tali valori.
    Innanzitutto, limitiamo i valori ai soli numeri (userò cper count):

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

    E quindi limitare il valore di conteggio solo a valori positivi:

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

Questa funzione accetterà senza problemi 0 o qualsiasi testo (senza errori):

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

Rimuovere il echo \quando hai testato la funzione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.