Wie ändere ich eine globale Variable innerhalb einer Funktion in bash?

104

Ich arbeite damit:

GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

Ich habe ein Skript wie unten:

#!/bin/bash

e=2

function test1() {
  e=4
  echo "hello"
}

test1 
echo "$e"

Welches kehrt zurück:

hello
4

Wenn ich aber das Ergebnis der Funktion einer Variablen zuordne, wird die globale Variable enicht geändert:

#!/bin/bash

e=2

function test1() {
  e=4
  echo "hello"
}

ret=$(test1)

echo "$ret"
echo "$e"

Kehrt zurück:

hello
2

Ich habe von der Verwendung von eval in diesem Fall gehört, also habe ich dies getan in test1:

eval 'e=4'

Aber das gleiche Ergebnis.

Können Sie mir erklären, warum es nicht geändert wird? Wie kann ich das Echo der test1Funktion in speichern retund auch die globale Variable ändern?

harrison4
quelle
Müssen Sie Hallo zurückgeben? Sie könnten einfach $ e wiederholen, damit es zurückkehrt. Oder alles wiedergeben, was Sie wollen, und dann das Ergebnis analysieren?

Antworten:

97

Wenn Sie eine Befehlssubstitution (dh das $(...)Konstrukt) verwenden, erstellen Sie eine Unterschale. Subshells erben Variablen von ihren übergeordneten Shells, dies funktioniert jedoch nur in einer Richtung: Eine Subshell kann die Umgebung ihrer übergeordneten Shell nicht ändern. Ihre Variable ewird in einer Subshell festgelegt, nicht jedoch in der übergeordneten Shell. Es gibt zwei Möglichkeiten, Werte von einer Subshell an das übergeordnete Element zu übergeben. Zuerst können Sie etwas an stdout ausgeben und es dann mit einer Befehlssubstitution erfassen:

myfunc() {
    echo "Hello"
}

var="$(myfunc)"

echo "$var"

Gibt:

Hello

Für einen numerischen Wert von 0-255 können Sie returndie Nummer als Exit-Status übergeben:

mysecondfunc() {
    echo "Hello"
    return 4
}

var="$(mysecondfunc)"
num_var=$?

echo "$var - num is $num_var"

Gibt:

Hello - num is 4
Josh Jolly
quelle
Vielen Dank für den Punkt, aber ich muss ein String-Array zurückgeben und innerhalb der Funktion zwei globalen String-Arrays Elemente hinzufügen.
Harrison4
3
Sie erkennen, dass alle globalen Variablen aktualisiert werden, wenn Sie die Funktion nur ausführen, ohne sie einer Variablen zuzuweisen. Anstatt ein String-Array zurückzugeben, können Sie das String-Array in der Funktion einfach aktualisieren und nach Abschluss der Funktion einer anderen Variablen zuweisen.
@ JohnDoe: Sie können kein "String-Array" von einer Funktion zurückgeben. Sie können lediglich eine Zeichenfolge drucken. Sie können jedoch setarray() { declare -ag "$1=(a b c)"; }
Folgendes
34

Dies erfordert Bash 4.1, wenn Sie {fd}oder verwenden local -n.

Der Rest sollte in Bash 3.x funktionieren, hoffe ich. Ich bin mir aufgrund dessen nicht ganz sicher printf %q- dies könnte eine Bash 4-Funktion sein.

Zusammenfassung

Ihr Beispiel kann wie folgt geändert werden, um den gewünschten Effekt zu archivieren:

# Add following 4 lines:
_passback() { while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }
passback() { _passback "$@" "$?"; }
_capture() { { out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)"; }
capture() { eval "$(_capture "$@")"; }

e=2

# Add following line, called "Annotation"
function test1_() { passback e; }
function test1() {
  e=4
  echo "hello"
}

# Change following line to:
capture ret test1 

echo "$ret"
echo "$e"

druckt wie gewünscht:

hello
4

Beachten Sie, dass diese Lösung:

  • Funktioniert auch für e=1000.
  • Konserviert, $?wenn Sie brauchen$?

Die einzigen schlechten Nebenwirkungen sind:

  • Es braucht eine moderne bash.
  • Es gabelt sich ziemlich oft.
  • Es benötigt die Anmerkung (benannt nach Ihrer Funktion, mit einem Zusatz _)
  • Es opfert den Dateideskriptor 3.
    • Sie können es bei Bedarf in ein anderes FD ändern.
      • In _capturenur alle Vorkommen von ersetzen 3mit einer anderen (höheren) Nummer.

Im Folgenden (was ziemlich lang ist, tut mir leid) wird hoffentlich erklärt, wie dieses Rezept auch auf andere Skripte übertragen werden kann.

Das Problem

d() { let x++; date +%Y%m%d-%H%M%S; }

x=0
d1=$(d)
d2=$(d)
d3=$(d)
d4=$(d)
echo $x $d1 $d2 $d3 $d4

Ausgänge

0 20171129-123521 20171129-123521 20171129-123521 20171129-123521

während die gewünschte Ausgabe ist

4 20171129-123521 20171129-123521 20171129-123521 20171129-123521

Die Ursache des Problems

Shell-Variablen (oder allgemein die Umgebung) werden von elterlichen Prozessen an untergeordnete Prozesse übergeben, jedoch nicht umgekehrt.

Wenn Sie eine Ausgabeerfassung durchführen, wird diese normalerweise in einer Subshell ausgeführt, sodass die Rückgabe von Variablen schwierig ist.

Einige sagen Ihnen sogar, dass es unmöglich ist, das Problem zu beheben. Das ist falsch, aber es ist seit langem bekannt, dass es schwierig ist, ein Problem zu lösen.

Es gibt verschiedene Möglichkeiten, wie Sie es am besten lösen können. Dies hängt von Ihren Anforderungen ab.

Hier finden Sie eine Schritt-für-Schritt-Anleitung.

Rückgabe von Variablen an die elterliche Hülle

Es gibt eine Möglichkeit, Variablen an eine übergeordnete Shell zurückzugeben. Dies ist jedoch ein gefährlicher Weg, da dies verwendet eval. Wenn Sie es nicht richtig machen, riskieren Sie viele böse Dinge. Aber wenn es richtig gemacht wird, ist dies absolut sicher, vorausgesetzt, es gibt keinen Fehler bash.

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }

d() { let x++; d=$(date +%Y%m%d-%H%M%S); _passback x d; }

x=0
eval `d`
d1=$d
eval `d`
d2=$d
eval `d`
d3=$d
eval `d`
d4=$d
echo $x $d1 $d2 $d3 $d4

druckt

4 20171129-124945 20171129-124945 20171129-124945 20171129-124945

Beachten Sie, dass dies auch für gefährliche Dinge funktioniert:

danger() { danger="$*"; passback danger; }
eval `danger '; /bin/echo *'`
echo "$danger"

druckt

; /bin/echo *

Dies liegt daran printf '%q', dass Sie alles so zitieren, dass Sie es sicher in einem Shell-Kontext wiederverwenden können.

Aber das ist ein Schmerz in der a ..

Dies sieht nicht nur hässlich aus, es ist auch viel zu tippen, daher ist es fehleranfällig. Nur ein einziger Fehler und du bist zum Scheitern verurteilt, oder?

Nun, wir sind auf Shell-Ebene, also können Sie es verbessern. Denken Sie nur an eine Schnittstelle, die Sie sehen möchten, und dann können Sie sie implementieren.

Augment, wie die Shell Dinge verarbeitet

Lassen Sie uns einen Schritt zurücktreten und über eine API nachdenken, mit der wir leicht ausdrücken können, was wir tun möchten.

Was wollen wir mit der d()Funktion machen?

Wir wollen die Ausgabe in einer Variablen erfassen. OK, dann implementieren wir eine API für genau dies:

# This needs a modern bash 4.3 (see "help declare" if "-n" is present,
# we get rid of it below anyway).
: capture VARIABLE command args..
capture()
{
local -n output="$1"
shift
output="$("$@")"
}

Jetzt anstatt zu schreiben

d1=$(d)

wir können schreiben

capture d1 d

Nun, es sieht so aus, als hätten wir nicht viel geändert, da die Variablen wiederum nicht an ddie übergeordnete Shell zurückgegeben werden und wir etwas mehr eingeben müssen.

Jetzt können wir jedoch die volle Kraft der Shell darauf werfen, da sie gut in eine Funktion eingewickelt ist.

Denken Sie an eine einfach wiederverwendbare Oberfläche

Eine zweite Sache ist, dass wir trocken sein wollen (Wiederholen Sie sich nicht). Wir wollen also definitiv nicht so etwas tippen

x=0
capture1 x d1 d
capture1 x d2 d
capture1 x d3 d
capture1 x d4 d
echo $x $d1 $d2 $d3 $d4

Das xhier ist nicht nur redundant, es ist auch fehleranfällig, immer im richtigen Kontext zu wiederholen. Was ist, wenn Sie es 1000 Mal in einem Skript verwenden und dann eine Variable hinzufügen? Sie möchten definitiv nicht alle 1000 Standorte ändern, an denen ein Anruf dbeteiligt ist.

Also lass das xweg, damit wir schreiben können:

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }

d() { let x++; output=$(date +%Y%m%d-%H%M%S); _passback output x; }

xcapture() { local -n output="$1"; eval "$("${@:2}")"; }

x=0
xcapture d1 d
xcapture d2 d
xcapture d3 d
xcapture d4 d
echo $x $d1 $d2 $d3 $d4

Ausgänge

4 20171129-132414 20171129-132414 20171129-132414 20171129-132414

Das sieht schon sehr gut aus. (Aber es gibt immer noch das, local -nwas in oder common bash3.x nicht funktioniert )

Vermeiden Sie Änderungen d()

Die letzte Lösung weist einige große Mängel auf:

  • d() muss geändert werden
  • Es müssen einige interne Details von verwendet werden xcapture, um die Ausgabe zu übergeben.
    • Beachten Sie, dass dies eine benannte Variable beschattet (brennt) output, sodass wir diese niemals zurückgeben können.
  • Es muss mit kooperieren _passback

Können wir das auch loswerden?

Natürlich können wir! Wir sind in einer Hülle, also gibt es alles, was wir brauchen, um dies zu erreichen.

Wenn Sie sich den Anruf etwas genauer evalansehen, können Sie feststellen, dass wir an diesem Standort 100% Kontrolle haben. "Drinnen" befinden evalwir uns in einer Unterschale, sodass wir alles tun können, was wir wollen, ohne Angst zu haben, der elterlichen Hülle etwas Schlechtes anzutun.

Ja, schön, also fügen wir einen weiteren Wrapper hinzu, jetzt direkt in eval:

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
# !DO NOT USE!
_xcapture() { "${@:2}" > >(printf "%q=%q;" "$1" "$(cat)"); _passback x; }  # !DO NOT USE!
# !DO NOT USE!
xcapture() { eval "$(_xcapture "$@")"; }

d() { let x++; date +%Y%m%d-%H%M%S; }

x=0
xcapture d1 d
xcapture d2 d
xcapture d3 d
xcapture d4 d
echo $x $d1 $d2 $d3 $d4

druckt

4 20171129-132414 20171129-132414 20171129-132414 20171129-132414                                                    

Dies hat jedoch wiederum einige große Nachteile:

  • Die !DO NOT USE!Markierungen sind da, weil es eine sehr schlechte Rennbedingung gibt, die Sie nicht leicht sehen können:
    • Das >(printf ..)ist ein Hintergrundjob. Es wird also möglicherweise noch ausgeführt, während das ausgeführt _passback xwird.
    • Sie können dies selbst sehen, wenn Sie ein sleep 1;vor printfoder hinzufügen _passback. _xcapture a d; echodann Ausgänge xbzw. azuerst.
  • Das _passback xsollte nicht Teil sein _xcapture, da dies die Wiederverwendung dieses Rezepts erschwert.
  • Wir haben hier auch eine nicht befestigte Gabel $(cat), aber da diese Lösung ist, habe !DO NOT USE!ich den kürzesten Weg genommen.

Dies zeigt jedoch, dass wir dies ohne Änderung an d()(und ohne local -n) tun können !

Bitte beachten Sie, dass wir nicht unbedingt brauchen _xcapture, da wir alles richtig in die geschrieben haben könnten eval.

Dies ist jedoch normalerweise nicht sehr gut lesbar. Und wenn Sie in ein paar Jahren zu Ihrem Skript zurückkehren, möchten Sie es wahrscheinlich ohne große Probleme wieder lesen können.

Repariere das Rennen

Lassen Sie uns nun den Rennzustand korrigieren.

Der Trick könnte darin bestehen, zu warten, bis printfSTDOUT geschlossen ist, und dann auszugeben x.

Es gibt viele Möglichkeiten, dies zu archivieren:

  • Sie können keine Shell-Pipes verwenden, da Pipes in unterschiedlichen Prozessen ausgeführt werden.
  • Man kann temporäre Dateien verwenden,
  • oder so etwas wie eine Sperrdatei oder ein Fifo. Dies ermöglicht es, auf das Schloss oder Fifo zu warten,
  • oder verschiedene Kanäle, um die Informationen auszugeben und dann die Ausgabe in einer korrekten Reihenfolge zusammenzusetzen.

Das Folgen des letzten Pfades könnte folgendermaßen aussehen (beachten Sie, dass dies der printfletzte ist, da dies hier besser funktioniert):

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }

_xcapture() { { printf "%q=%q;" "$1" "$("${@:2}" 3<&-; _passback x >&3)"; } 3>&1; }

xcapture() { eval "$(_xcapture "$@")"; }

d() { let x++; date +%Y%m%d-%H%M%S; }

x=0
xcapture d1 d
xcapture d2 d
xcapture d3 d
xcapture d4 d
echo $x $d1 $d2 $d3 $d4

Ausgänge

4 20171129-144845 20171129-144845 20171129-144845 20171129-144845

Warum ist das richtig?

  • _passback x spricht direkt mit STDOUT.
  • Da STDOUT jedoch im inneren Befehl erfasst werden muss, "speichern" wir es zuerst in FD3 (Sie können natürlich auch andere verwenden) mit '3> & 1' und verwenden es dann mit wieder >&3.
  • Das $("${@:2}" 3<&-; _passback x >&3)endet nach dem _passback, wenn die Unterschale STDOUT schließt.
  • Das printfkann also nicht vor dem passieren _passback, egal wie lange es _passbackdauert.
  • Beachten Sie, dass der printfBefehl nicht ausgeführt wird, bevor die vollständige Befehlszeile zusammengestellt wurde, sodass wir keine Artefakte sehen können printf, unabhängig davon, wie sie printfimplementiert werden.

Daher zuerst _passbackausgeführt, dann die printf.

Dies löst das Rennen und opfert einen festen Dateideskriptor 3. Sie können natürlich einen anderen Dateideskriptor auswählen, falls FD3 in Ihrem Shellscript nicht frei ist.

Bitte beachten Sie auch den 3<&-Schutz von FD3, der an die Funktion übergeben werden soll.

Machen Sie es allgemeiner

_captureenthält Teile, die d()aus Sicht der Wiederverwendbarkeit zu gehören , was schlecht ist. Wie kann man das lösen?

Nun, machen Sie es auf die verzweifelte Weise, indem Sie eine weitere Sache einführen, eine zusätzliche Funktion, die die richtigen Dinge zurückgeben muss, die nach der ursprünglichen Funktion mit _Anhang benannt ist.

Diese Funktion wird nach der realen Funktion aufgerufen und kann die Dinge erweitern. Auf diese Weise kann dies als eine Anmerkung gelesen werden, so dass es sehr gut lesbar ist:

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
_capture() { { printf "%q=%q;" "$1" "$("${@:2}" 3<&-; "$2_" >&3)"; } 3>&1; }
capture() { eval "$(_capture "$@")"; }

d_() { _passback x; }
d() { let x++; date +%Y%m%d-%H%M%S; }

x=0
capture d1 d
capture d2 d
capture d3 d
capture d4 d
echo $x $d1 $d2 $d3 $d4

druckt immer noch

4 20171129-151954 20171129-151954 20171129-151954 20171129-151954

Ermöglichen Sie den Zugriff auf den Rückkehrcode

Es fehlt nur ein bisschen:

v=$(fn)setzt $?auf das, was fnzurückgekehrt ist. Also willst du das wahrscheinlich auch. Es bedarf jedoch einiger größerer Anpassungen:

# This is all the interface you need.
# Remember, that this burns FD=3!
_passback() { while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }
passback() { _passback "$@" "$?"; }
_capture() { { out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)"; }
capture() { eval "$(_capture "$@")"; }

# Here is your function, annotated with which sideffects it has.
fails_() { passback x y; }
fails() { x=$1; y=69; echo FAIL; return 23; }

# And now the code which uses it all
x=0
y=0
capture wtf fails 42
echo $? $x $y $wtf

druckt

23 42 69 FAIL

Es gibt noch viel Raum für Verbesserungen

  • _passback() kann mit beseitigt werden passback() { set -- "$@" "$?"; while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }
  • _capture() kann mit beseitigt werden capture() { eval "$({ out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)")"; }

  • Die Lösung verschmutzt einen Dateideskriptor (hier 3), indem sie ihn intern verwendet. Sie müssen dies berücksichtigen, wenn Sie FDs passieren.
    Beachten Sie, dass in bashVersion 4.1 und höher {fd}nicht verwendete FD verwendet werden müssen.
    (Vielleicht füge ich hier eine Lösung hinzu, wenn ich vorbeikomme.)
    Beachten Sie, dass ich sie deshalb in separate Funktionen einfüge _capture, weil es möglich ist, alles in eine Zeile zu packen, aber das Lesen und Verstehen immer schwieriger macht

  • Vielleicht möchten Sie auch STDERR der aufgerufenen Funktion erfassen. Oder Sie möchten sogar mehr als einen Dateideskriptor von und an Variablen übergeben.
    Ich habe noch keine Lösung, aber hier ist eine Möglichkeit, mehr als eine FD abzufangen , sodass wir die Variablen wahrscheinlich auch auf diese Weise zurückgeben können.

Vergessen Sie auch nicht:

Dies muss eine Shell-Funktion aufrufen, keinen externen Befehl.

Es gibt keine einfache Möglichkeit, Umgebungsvariablen an externe Befehle zu übergeben. (Damit LD_PRELOAD=sollte es aber möglich sein!) Aber das ist dann etwas ganz anderes.

Letzte Worte

Dies ist nicht die einzig mögliche Lösung. Es ist ein Beispiel für eine Lösung.

Wie immer haben Sie viele Möglichkeiten, Dinge in der Shell auszudrücken. Fühlen Sie sich also frei, sich zu verbessern und etwas Besseres zu finden.

Die hier vorgestellte Lösung ist alles andere als perfekt:

  • Es war fast gar nicht testet, also bitte verzeihen Sie Tippfehler.
  • Es gibt viel Raum für Verbesserungen, siehe oben.
  • Es verwendet viele Funktionen aus der Moderne bash, so dass es wahrscheinlich schwierig ist, sie auf andere Shells zu übertragen.
  • Und es könnte einige Macken geben, an die ich nicht gedacht habe.

Ich denke jedoch, dass es ziemlich einfach zu bedienen ist:

  • Fügen Sie nur 4 Zeilen "Bibliothek" hinzu.
  • Fügen Sie nur 1 Zeile "Anmerkung" für Ihre Shell-Funktion hinzu.
  • Opfert nur einen Dateideskriptor vorübergehend.
  • Und jeder Schritt sollte auch Jahre später leicht zu verstehen sein.
Tino
quelle
2
Sie sind fantastisch
Eliran Malka
14

Vielleicht können Sie eine Datei verwenden, in eine Datei innerhalb der Funktion schreiben und danach aus einer Datei lesen. Ich habe ezu einem Array gewechselt . In diesem Beispiel werden beim Zurücklesen des Arrays Leerzeichen als Trennzeichen verwendet.

#!/bin/bash

declare -a e
e[0]="first"
e[1]="secondddd"

function test1 () {
 e[2]="third"
 e[1]="second"
 echo "${e[@]}" > /tmp/tempout
 echo hi
}

ret=$(test1)

echo "$ret"

read -r -a e < /tmp/tempout
echo "${e[@]}"
echo "${e[0]}"
echo "${e[1]}"
echo "${e[2]}"

Ausgabe:

hi
first second third
first
second
third
Ashkan
quelle
13

Was Sie tun, führen Sie test1 aus

$(test1)

in einer Sub-Shell (untergeordnete Shell) und untergeordnete Shells können im übergeordneten Element nichts ändern .

Sie finden es im Bash- Handbuch

Bitte überprüfen Sie: Die Dinge führen hier zu einer Unterschale

PradyJord
quelle
7

Ich hatte ein ähnliches Problem, als ich temporäre Dateien, die ich erstellt hatte, automatisch entfernen wollte. Die Lösung, die ich gefunden habe, bestand nicht darin, eine Befehlssubstitution zu verwenden, sondern den Namen der Variablen, die das Endergebnis enthalten soll, an die Funktion zu übergeben. Z.B

#! /bin/bash

remove_later=""
new_tmp_file() {
    file=$(mktemp)
    remove_later="$remove_later $file"
    eval $1=$file
}
remove_tmp_files() {
    rm $remove_later
}
trap remove_tmp_files EXIT

new_tmp_file tmpfile1
new_tmp_file tmpfile2

In Ihrem Fall wäre das also:

#!/bin/bash

e=2

function test1() {
  e=4
  eval $1="hello"
}

test1 ret

echo "$ret"
echo "$e"

Funktioniert und hat keine Einschränkungen für den "Rückgabewert".

Elmar Zander
quelle
1

Dies liegt daran, dass die Befehlssubstitution in einer Unterschale ausgeführt wird. Während die Unterschale die Variablen erbt, gehen Änderungen an ihnen verloren, wenn die Unterschale endet.

Referenz :

Befehlssubstitution , in Klammern gruppierte Befehle und asynchrone Befehle werden in einer Subshell-Umgebung aufgerufen, die ein Duplikat der Shell-Umgebung ist

Ein Programmierer
quelle
@ JohnDoe Ich bin nicht sicher, ob es möglich ist. Möglicherweise müssen Sie Ihr Design des Skripts überdenken.
Einige Programmierer Typ
Oh, aber ich muss ein globales Array innerhalb einer Funktion zuordnen. Wenn nicht, müsste ich viel Code wiederholen (den Code der Funktion -30 Zeilen- 15 Mal wiederholen - einmal pro Aufruf-). Es gibt keinen anderen Weg, nicht wahr?
Harrison4
1

Eine Lösung für dieses Problem, ohne komplexe Funktionen einführen und die ursprüngliche stark ändern zu müssen, besteht darin, den Wert in einer temporären Datei zu speichern und bei Bedarf zu lesen / schreiben.

Dieser Ansatz hat mir sehr geholfen, als ich eine Bash-Funktion verspotten musste, die in einem Fledermaus-Testfall mehrmals aufgerufen wurde.

Zum Beispiel könnten Sie haben:

# Usage read_value path_to_tmp_file
function read_value {
  cat "${1}"
}

# Usage: set_value path_to_tmp_file the_value
function set_value {
  echo "${2}" > "${1}"
}
#----

# Original code:

function test1() {
  e=4
  set_value "${tmp_file}" "${e}"
  echo "hello"
}


# Create the temp file
# Note that tmp_file is available in test1 as well
tmp_file=$(mktemp)

# Your logic
e=2
# Store the value
set_value "${tmp_file}" "${e}"

# Run test1
test1

# Read the value modified by test1
e=$(read_value "${tmp_file}")
echo "$e"

Der Nachteil ist, dass Sie möglicherweise mehrere temporäre Dateien für verschiedene Variablen benötigen. Außerdem müssen Sie möglicherweise einen syncBefehl ausgeben, um den Inhalt auf der Festplatte zwischen einem Schreib- und einem Lesevorgang beizubehalten.

Fabio
quelle
-1

Sie können jederzeit einen Alias ​​verwenden:

alias next='printf "blah_%02d" $count;count=$((count+1))'
Dino Dini
quelle