/foo/fizzbuzz.bar
Wie würde ich bei einem String-Dateipfad wie z. B. bash verwenden, um nur den fizzbuzz
Teil des Strings zu extrahieren ?
/foo/fizzbuzz.bar
Wie würde ich bei einem String-Dateipfad wie z. B. bash verwenden, um nur den fizzbuzz
Teil des Strings zu extrahieren ?
Antworten:
Hier erfahren Sie, wie Sie dies mit den Operatoren # und% in Bash tun.
$ x="/foo/fizzbuzz.bar"
$ y=${x%.bar}
$ echo ${y##*/}
fizzbuzz
${x%.bar}
könnte auch sein ${x%.*}
, alles nach einem Punkt ${x%%.*}
zu entfernen oder alles nach dem ersten Punkt zu entfernen.
Beispiel:
$ x="/foo/fizzbuzz.bar.quux"
$ y=${x%.*}
$ echo $y
/foo/fizzbuzz.bar
$ y=${x%%.*}
$ echo $y
/foo/fizzbuzz
Die Dokumentation finden Sie im Bash-Handbuch . Sucht ${parameter%word}
und ${parameter%%word}
Hinterteil Anpassungsabschnitt.
Schauen Sie sich den Befehl basename an:
NAME="$(basename /foo/fizzbuzz.bar .bar)"
Mit dem Basisnamen habe ich Folgendes verwendet, um dies zu erreichen:
for file in *; do
ext=${file##*.}
fname=`basename $file $ext`
# Do things with $fname
done;
Dies erfordert keine vorherige Kenntnis der Dateierweiterung und funktioniert auch dann, wenn Sie einen Dateinamen haben, dessen Dateiname Punkte enthält (vor der Erweiterung). es erfordert das Programmbasename
, aber dies ist Teil der GNU-Coreutils, daher sollte es mit jeder Distribution ausgeliefert werden.
fname=`basename $file .$ext`
Pure Bash Way:
~$ x="/foo/bar/fizzbuzz.bar.quux.zoom";
~$ y=${x/\/*\//};
~$ echo ${y/.*/};
fizzbuzz
Diese Funktionalität wird auf man bash unter "Parametererweiterung" erläutert. Non-Bash-Wege gibt es zuhauf: awk, perl, sed und so weiter.
EDIT: Arbeiten mit Punkten in der Datei Suffixe und nicht das Suffix (Erweiterung) wissen müssen, aber nicht Arbeit mit Punkten im Namen selbst.
Die Funktionen basename und dirname sind genau das, wonach Sie suchen:
mystring=/foo/fizzbuzz.bar
echo basename: $(basename "${mystring}")
echo basename + remove .bar: $(basename "${mystring}" .bar)
echo dirname: $(dirname "${mystring}")
Hat Ausgabe:
basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo
mystring=$1
dem aktuellen konstanten Wert aus (wodurch mehrere Warnungen unterdrückt werden, wobei sichergestellt ist , dass keine Leerzeichen / Glob-Zeichen / usw. enthalten sind), und beheben Sie die Probleme findet?
echo "basename: $(basename "$mystring")"
- Auf diese Weise, wenn mystring='/foo/*'
Sie die *
Dateien nach basename
Abschluss nicht durch eine Liste von Dateien im aktuellen Verzeichnis ersetzen lassen .
Verwenden von basename
davon , dass Sie die Dateierweiterung kennen, nicht wahr?
Und ich glaube, dass die verschiedenen Vorschläge für reguläre Ausdrücke nicht mit einem Dateinamen fertig werden, der mehr als ein "enthält".
Das Folgende scheint mit Doppelpunkten fertig zu werden. Oh, und Dateinamen, die selbst ein "/" enthalten (nur für Tritte)
Um Pascal zu paraphrasieren: "Entschuldigung, dieses Skript ist so lang. Ich hatte keine Zeit, es kürzer zu machen."
#!/usr/bin/perl
$fullname = $ARGV[0];
($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
print $basename . "\n";
Neben die POSIX - konformen Syntax in verwendete diese Antwort ,
basename string [suffix]
wie in
basename /foo/fizzbuzz.bar .bar
GNUbasename
unterstützt eine andere Syntax:
basename -s .bar /foo/fizzbuzz.bar
mit dem gleichen Ergebnis. Der Unterschied und Vorteil ist , dass -s
bedeutet -a
, die mehrere Argumente unterstützt:
$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar
fizzbuzz
foobar
Dies kann sogar -z
datensamensicher gemacht werden, indem die Ausgabe mit der Option durch NUL-Bytes getrennt wird , beispielsweise für diese Dateien, die Leerzeichen, Zeilenumbrüche und Glob-Zeichen enthalten (zitiert durch ls
):
$ ls has*
'has'$'\n''newline.bar' 'has space.bar' 'has*.bar'
Einlesen in ein Array:
$ readarray -d $'\0' arr < <(basename -zs .bar has*)
$ declare -p arr
declare -a arr=([0]=$'has\nnewline' [1]="has space" [2]="has*")
readarray -d
erfordert Bash 4.4 oder neuer. Für ältere Versionen müssen wir eine Schleife ausführen:
while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)
Wenn Sie den in anderen Posts vorgeschlagenen Basisnamen nicht verwenden können, können Sie immer sed verwenden. Hier ist ein (hässliches) Beispiel. Es ist nicht das Beste, aber es funktioniert, indem die gewünschte Zeichenfolge extrahiert und die Eingabe durch die gewünschte Zeichenfolge ersetzt wird.
echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'
Welches erhalten Sie die Ausgabe
Fizzbuzz
Hüten Sie sich vor der vorgeschlagenen Perl-Lösung: Sie entfernt alles nach dem ersten Punkt.
$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some
Wenn Sie es mit Perl machen wollen, funktioniert dies:
$ echo some.file.with.dots | perl -pe 's/(.*)\..*$/$1/;s{^.*/}{}'
some.file.with
Wenn Sie jedoch Bash verwenden, sind die Lösungen mit y=${x%.*}
(oder basename "$x" .ext
wenn Sie die Erweiterung kennen) viel einfacher.
Der Basisname macht das, entfernt den Pfad. Es wird auch das Suffix entfernt, wenn es angegeben ist und mit dem Suffix der Datei übereinstimmt, aber Sie müssten das Suffix kennen, das Sie dem Befehl geben können. Andernfalls können Sie mv verwenden und herausfinden, wie der neue Name anders lauten soll.
Kombinieren Sie die am besten bewertete Antwort mit der am zweitbesten bewerteten Antwort, um den Dateinamen ohne den vollständigen Pfad zu erhalten:
$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
${parameter%word}
und${parameter%%word}
in Hinterteil Anpassungsabschnitt.