it-swarm.com.de

Wie entferne ich das Dateisuffix und den Pfadteil aus einer Pfadzeichenfolge in Bash?

Gegeben ein String-Dateipfad wie /foo/fizzbuzz.bar, wie würde ich bash benutzen, um nur den fizzbuzz Teil der besagten Zeichenkette zu extrahieren?

356

So geht's mit den Operatoren # und% in Bash.

$ x="/foo/fizzbuzz.bar"
$ y=${x%.bar}
$ echo ${y##*/}
fizzbuzz

${x%.bar} Könnte auch ${x%.*} Sein, um alles nach einem Punkt zu entfernen, oder ${x%%.*}, Um 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

Dokumentation finden Sie im Bash-Handbuch . Suchen Sie nach den Abschlussteilen ${parameter%Word} Und ${parameter%%Word}.

505
Zan Lynx

schauen Sie sich den Befehl basename an:

NAME=$(basename /foo/fizzbuzz.bar .bar)
196
zigdon

Pure Bash, durchgeführt in zwei getrennten Vorgängen:

  1. Entfernen Sie den Pfad aus einer Pfadzeichenfolge:

    path=/foo/bar/bim/baz/file.gif
    
    file=${path##*/}  
    #$file is now 'file.gif'
    
  2. Entfernen Sie die Erweiterung von einer Pfadzeichenfolge:

    base=${file%.*}
    #${base} is now 'file'.
    
34
Param

Unter Verwendung des Basisnamens 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 A-priori-Kenntnis der Dateierweiterung und funktioniert auch dann, wenn der Dateiname einen Punkt enthält (vor der Erweiterung). es erfordert zwar das Programm basename, aber dies ist Teil der GNU= coreutils, daher sollte es mit jeder Distribution ausgeliefert werden.

15
mike

Pure Bash Way:

~$ x="/foo/bar/fizzbuzz.bar.quux.zoom"; 
~$ y=${x/\/*\//}; 
~$ echo ${y/.*/}; 
fizzbuzz

Diese Funktionalität wird auf man bash unter "Parameter Expansion" erklärt. Non-bash-Methoden gibt es zuhauf: awk, Perl, sed und so weiter.

BEARBEITEN: Funktioniert mit Punkten in der Datei Suffixe und muss das Suffix (Erweiterung) nicht kennen, aber nicht funktioniert mit Punkten in der Datei Name selbst.

12
Vinko Vrsalovic

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
10
Jerub

Zusätzlich zur POSIX-konformen Syntax , die in dieser Antwort verwendet wird,

basename string [suffix]

wie in

basename /foo/fizzbuzz.bar .bar

GNU basename unterstützt eine andere Syntax:

basename -s .bar /foo/fizzbuzz.bar

mit dem gleichen Ergebnis. Der Unterschied und Vorteil ist, dass -s-a Impliziert, das mehrere Argumente unterstützt:

$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar
fizzbuzz
foobar

Dies kann sogar durch Trennen der Ausgabe mit NUL-Bytes mit der Option -z Dateinamensicher gemacht werden, z. B. für diese Dateien mit Leerzeichen, Zeilenumbrüchen und Glob-Zeichen (in Anführungszeichen von 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 Benötigt Bash 4.4 oder neuer. Für ältere Versionen müssen wir folgende Schleife ausführen:

while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)
3
Benjamin W.

Wenn Sie den in anderen Beiträgen 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 wird Ihnen die Ausgabe erhalten

fizzbuzz

3
nymacro

Die Verwendung von basename setzt voraus, 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 mit mehr als einem "."

Das Folgende scheint mit doppelten Punkten fertig zu werden. Oh, und Dateinamen, die selbst ein "/" enthalten (nur für Kicks)

Um Pascal zu paraphrasieren: "Sorry, dieses Skript ist so lang. Ich hatte keine Zeit, es zu verkürzen."


  #!/usr/bin/Perl
  $fullname = $ARGV[0];
  ($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
  ($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
  print $basename . "\n";
 
3
Perl -pe 's/\..*$//;s{^.*/}{}'
3
mopoke

Achten Sie auf die vorgeschlagene 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 tun möchten, funktioniert dies:

$ echo some.file.with.dots | Perl -pe 's/(.*)\..*$/$1/;s{^.*/}{}'
some.file.with

Wenn Sie jedoch Bash verwenden, werden die Lösungen mit y=${x%.*} (oder basename "$x" .ext wenn du die erweiterung kennst) sind viel einfacher.

2
mivk

Der Basisname macht das, entfernt den Pfad. Es wird auch das Suffix entfernen, wenn es angegeben wurde und mit dem Suffix der Datei übereinstimmt, aber Sie müssten das Suffix kennen, um es dem Befehl zu geben. Andernfalls können Sie mv verwenden und herausfinden, wie der neue Name anders lauten soll.

1
waynecolvin

Kombinieren Sie die bestbewertete Antwort mit der zweitbestbewerteten Antwort, um den Dateinamen ohne den vollständigen Pfad zu erhalten:

$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
1
c.gutierrez