Verwenden der Bash-Variablensubstitution anstelle von cut / awk

Kann ich die Bash-Variablensubstitution verwenden, um einen Teil einer Variablen basierend auf einem Delimeter zu extrahieren? Ich versuche, den unmittelbaren Verzeichnisnamen eines Dateinamens abzurufen (in diesem Fall foo).

$ filename=./foo/bar/baz.xml 

Ich weiß, ich könnte so etwas wie

echo $filename | cut -d "/" -f 2 

oder

echo $filename | awk -F "/" "{print $2}" 

tun, aber es “ s wird langsam zum Verzweigen awk / cut für mehrere Dateinamen.

Ich habe die verschiedenen Lösungen ein wenig profiliert unter Verwendung meiner realen Dateien:

echo | cut:

real 2m56.805s user 0m37.009s sys 1m26.067s 

echo | awk:

real 2m56.282s user 0m38.157s sys 1m31.016s 

@steeldrivers Variablensubstitution / Shell-Parametererweiterung:

real 0m0.660s user 0m0.421s sys 0m0.235s 

@jai_s IFS-Wrangling:

real 1m26.243s user 0m13.751s sys 0m28.969s 

Beide Vorschläge waren eine enorme Verbesserung gegenüber meinen bestehenden Ideen, aber die Variablensubstitution ist am schnellsten, weil dies nicht der Fall ist Forken Sie neue Prozesse.

Kommentare

  • gnu.org/software/bash/manual / html_node / …
  • Senden Sie alle Dateinamen an einen Aufruf von awk und es ist erheblich schneller als jede Lösung in Pure Bash
  • Können Sie ein Array nicht verwenden, alle auf einmal ausführen und dann in ein neues Array einfügen?

Antwort

Sie können den kürzesten führenden Teilstring entfernen, der mit */

tmp="${filename#*/}" 

übereinstimmt, und dann den längsten entfernen nachfolgender Teilstring, der mit /*

Antwort

 echo $f a/b/c $ (IFS="/";set $f; echo $1) a $ (IFS="/";set $f; echo $2) b $ (IFS="/";set $f; echo $3) c 

mit Platzhalter, mit dem es zu funktionieren scheint doppelte oder einfache Anführungszeichen –

 f="a?b?c" $(IFS="?"; set $f; echo $1) a echo $f a*b*c (IFS="*"; set $f; echo $1) a 

Ja, Sie müssen das IFS auf den Standardwert zurücksetzen.

 unset IFS 

Kommentare

  • Oh, das gefällt mir.
  • Dies ist normalerweise auch meine bevorzugte Methode, aber denken Sie daran, dass Bash unterstützt nur $1 bis $9 mit dieser Syntax. Für 10. und spätere Argumente muss das Formular ${10} verwendet werden.
  • Funktioniert ' nicht, wenn $f enthält Platzhalter. Und Sie müssen anschließend IFS wiederherstellen (oder dies in einer Befehlssubstitution tun, um den Wert eines Felds zu erhalten, und das schließt nachfolgende Zeilenumbrüche ab).
  • Das Beispiel funktioniert isoliert (innerhalb von Git Bash unter Windows), aber wenn ich vom Befehl find eine Pipe bekomme, wird folgende Fehlermeldung angezeigt: echo: write error: Bad address.
  • Okay, sieht so aus Ich muss jedes Mal unset IFS.

Antwort

Feed die Liste zu awk, um sie zu beschleunigen:

awk -F "/" "{print $2}" < <(find /usr) awk -F "/" "{print $2}" < inputfile 

Demonstration:

time awk -F "/" "{print $2; SUM++} END {print "number of directories found: " SUM}" < <(find /usr -type d) usr usr . . number of directories found: 16748 real 0m8.910s user 0m0.050s sys 0m0.050s 

Antwort

Warum verwenden Sie nicht den Befehl“ dirname „anstelle all dieser awk / sed / Sachen schneiden?

filename=./foo/bar/baz.xml dirname $filename 

Ausbeuten:

./foo/bar 

Kommentare

  • In diesem Fall habe ich nach dem unmittelbaren Verzeichnis gesucht, nicht nach dem vollständigen Verzeichnispfad.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.