Können Sie mir diese drei Dinge in diesem Bash-Code erklären?

10

Ich habe eine functionin meiner .bashrcAkte. Ich weiß, was es tut, es erhöht X viele Verzeichnisse mitcd

Hier ist es:

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
}

Aber können Sie mir diese drei Dinge daraus erklären?

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

Warum nicht einfach so machen:

up()
{
    limit=$1

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

Verwendung:

<<<>>>~$ up 3
<<<>>>/$
etwas etwas
quelle

Antworten:

24
  1. d=$d/..fügt /..den aktuellen Inhalt der dVariablen hinzu. dbeginnt leer, dann macht es die erste Iteration /.., die zweite /../..usw.

  2. sed 's/^\///'Lässt den ersten fallen /, /../..wird also  ../..(dies kann durch eine Parametererweiterung erfolgen d=${d#/}).

  3. d=.. macht nur im Zusammenhang mit seinem Zustand Sinn:

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

    Dadurch wird sichergestellt, dass Sie, wenn des zu diesem Zeitpunkt leer ist, in das übergeordnete Verzeichnis wechseln. ( upohne Argument ist gleichbedeutend mit cd ...)

Dieser Ansatz ist besser als iterativ, cd ..da er cd -die Möglichkeit beibehält, in einem Schritt zum vorherigen Verzeichnis (aus Sicht des Benutzers) zurückzukehren.

Die Funktion kann vereinfacht werden:

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

Dies setzt voraus, dass wir mindestens eine Ebene nach oben gehen möchten, und fügt n - 1 Ebenen hinzu, sodass wir den führenden nicht entfernen /oder nach einem leeren suchen müssen $d.

Verwenden von Athena jot(das athena-jotPaket in Debian):

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

(basierend auf einer Variante von vorgeschlagen glenn jackman ).

Stephen Kitt
quelle
Ja, $OLDPWDich dachte daran, mit Füßen getreten zu werden. Und auf zsh mit cdset soll auch der dirstack verwendet werden.
Muru
Gibt es einen Grund für die Zuordnung $1zu , limitanstatt nur mit $1in der Schleife?
Nick Matteo
1
@kundor stellt sicher, dass der Standardwert 0 ist (siehe Shell-Arithmetik ). Wir könnten ${1:-1}stattdessen verwenden, wie in Glenns Variante.
Stephen Kitt
@kundor Auch menschliche Lesbarkeit. Eine gut benannte Variable sagt Ihnen, was die beabsichtigte Bedeutung oder der beabsichtigte Zweck des ersten Arguments ist, wenn Sie mit dem Lesen der Funktion beginnen, ohne zuerst wissen zu müssen, was die Funktion tut, oder den Code zu verstehen, um sie abzuleiten.
mtraceur
2

Aber können Sie mir diese drei Dinge daraus erklären?

  1. d = $ d / ..

    Dies verkettet den aktuellen Inhalt von var dmit /..und weist ihn wieder zu d.
    Das Endergebnis ist, deine wiederholte Zeichenfolge wie zu machen /../../../...

  2. sed 's / ^ ///'

    Entfernen Sie das führende Zeichen /aus der angegebenen Zeichenfolge d(echo $ d) in dem von Ihnen geposteten Code.
    Wahrscheinlich besser geschrieben sed 's|^/||', um den Backslash zu vermeiden.

    Eine Alternative (schneller und einfacher) ist das Schreiben d=${d#/}.

  3. d = ..

    Weisen Sie die Zeichenfolge ..an den var d.
    Dies ist nur sinnvoll, um sicherzustellen, dass dmindestens eine vorhanden ist, .. falls der Test if [ -z "$d" ]; thensignalisiert, dass die Variable dleer ist. Und das kann nur passieren, weil der Befehl sed ein Zeichen aus entfernt d.
    Wenn das Zeichen nicht aus d entfernt werden muss, ist sedoder nicht erforderlich if.


Der Code in Ihrer Frage wird immer um mindestens ein Verzeichnis nach oben verschoben.

Besser

  • local dreicht aus, um sicherzustellen, dass die Variable leer ist, nichts anderes wird benötigt.
    Lokal funktioniert jedoch nur in einigen Shells wie Bash oder Dash. Insbesondere hat ksh(as yash) keinen localBefehl. Eine tragbarere Lösung ist:

    [ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
  • Die for((Syntax ist nicht portierbar. Verwenden Sie besser so etwas wie:

    while [ "$((i+=1))" -lt "$limit" ]; do
  • Robust.
    Wenn die Werte für das erste Argument der Funktion negativ oder textuell sein können, sollte die Funktion robust sein, um diese Werte zu verarbeiten.
    Erstens können die Werte nur Zahlen begrenzen (Ich werde verwenden cfür count):

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

    Und dann beschränken Sie den Zählwert nur auf positive Werte:

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

Diese Funktion akzeptiert glücklicherweise 0 oder einen beliebigen Text (ohne Fehler):

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

Entfernen Sie die, echo \wenn Sie die Funktion getestet haben.

NotAnUnixNazi
quelle