Wie entferne ich die Dateiendung und Wegabschnitt von einer Pfadzeichenfolge in Bash?

StackOverflow https://stackoverflow.com/questions/125281

  •  02-07-2019
  •  | 
  •  

Frage

einen String Dateipfad wie /foo/fizzbuzz.bar gegeben, wie würde ich bash benutzen Sie einfach den fizzbuzz Teil der Zeichenfolge zu extrahieren?

War es hilfreich?

Lösung

Hier ist, wie es mit der # und% Operator in Bash zu tun.

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

${x%.bar} auch ${x%.*} werden könnte alles nach einem Punkt oder ${x%%.*} entfernen 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 kann in der

Andere Tipps

Blick auf den Basisnamen Befehl:

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

Reine bash, erfolgt in zwei getrennten Operationen:

  1. Entfernen Sie den Pfad von einem Pfad-String:

    path=/foo/bar/bim/baz/file.gif
    
    file=${path##*/}  
    #$file is now 'file.gif'
    
  2. die Erweiterung von einem Pfad-String entfernen:

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

Mit Basisnamen habe ich die dies zu erreichen folgt:

for file in *; do
    ext=${file##*.}
    fname=`basename $file $ext`

    # Do things with $fname
done;

Dies erfordert kein Vorwissen der Dateierweiterung und funktioniert auch, wenn Sie einen Dateinamen haben, die Punkte hat es in Dateiname ist (vor es ist Verlängerung); es tut, obwohl das Programm basename erfordern, aber dieser Teil des GNU coreutils ist, so dass es mit jedem Distro versenden soll.

Reine bash Art und Weise:

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

Diese Funktionalität wird auf den Menschen bash unter „Parameter Expansion“ erklärt. Nicht bash Möglichkeiten gibt es zuhauf: awk, Perl, Sed und so weiter

.

EDIT: Funktioniert mit Punkten in der Datei Suffixe und muss nicht mit dem Suffix (Erweiterung) kennen, aber nicht Arbeit mit Punkten in dem Name selbst.

Die Basisnamen und dirname Funktionen sind, was Sie nach:

mystring=/foo/fizzbuzz.bar
echo basename: $(basename "${mystring}")
echo basename + remove .bar: $(basename "${mystring}" .bar)
echo dirname: $(dirname "${mystring}")

Hat Ausgang:

basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo
perl -pe 's/\..*$//;s{^.*/}{}'

basename Mit geht davon aus, dass Sie wissen, was die Datei-Endung ist, nicht wahr?

Und ich glaube, dass die verschiedenen reguläre Ausdruck Vorschläge mit einem Dateinamen bewältigen nicht mehr als eine mit „“

Die folgende scheint mit Doppelpunkten zu bewältigen. Oh, und Dateinamen, die ein "/" selbst (nur für Kicks)

enthalten

Pascal paraphrasieren: „Sorry dieses Skript so lange. Ich habe keine Zeit, um es kürzer“


  #!/usr/bin/perl
  $fullname = $ARGV[0];
  ($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
  ($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
  print $basename . "\n";
 

Wenn Sie nicht verwenden können, wie in anderen Basisnamen Beiträgen vorgeschlagen, können Sie immer sed verwenden. Hier ist ein (hässlich) Beispiel. Es ist nicht die beste, aber es funktioniert, indem die gewünschte Zeichenfolge zu extrahieren und die Eingabe mit dem gesuchten Zeichenfolge zu ersetzen.

echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'

Welche erhalten Sie die Ausgabe

  
    

fizzbuzz

  

Neben der POSIX-konformen Syntax verwendet in diese Antwort ,

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 impliziert -a, die mehrere Argumente unterstützt:

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

Dies kann sogar Dateinamen sicher durch die Trennung der Ausgabe mit NUL Bytes mit der -z Option, zum Beispiel gemacht werden für diese Dateien Leerzeichen enthalten, Zeilenumbrüche und glob Zeichen (zitiert von ls):

$ ls has*
'has'$'\n''newline.bar'  'has space.bar'  'has*.bar'

Lesen 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 haben wir in einer Schleife:

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

Hüten Sie sich vor der vorgeschlagenen Perl-Lösung. Es etwas nach dem ersten Punkt entfernt

$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some

Wenn Sie es mit Perl tun wollen, das funktioniert:

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

Aber wenn Sie Bash verwenden, die Lösungen mit y=${x%.*} (oder basename "$x" .ext wenn Sie wissen, die Erweiterung) sind viel einfacher.

Der Basisname tut, den Pfad entfernt. Es wird auch das Suffix entfernen, wenn angegeben, und wenn es das Suffix der Datei übereinstimmt, aber Sie müßten das Suffix wissen, auf den Befehl zu geben. Ansonsten können Sie mv verwenden und herauszufinden, was der neue Name eine andere Art und Weise sein sollte.

die top-rated Antwort mit der zweit top-rated Antwort Kombinieren Sie die Dateinamen ohne den vollständigen Pfad zu bekommen:

$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top