it-swarm.com.de

Extrahieren Sie den Dateinamen ohne Pfad und Erweiterung in Bash

Gegebene Dateinamen wie diese:

/the/path/foo.txt
bar.txt

Ich hoffe ich bekomme:

foo
bar

Warum funktioniert das nicht?

#!/bin/bash

fullfile=$1
fname=$(basename $fullfile)
fbname=${fname%.*}
echo $fbname

Was ist der richtige Weg, um es zu tun?

287
neversaint

Sie müssen den externen Befehl basename nicht aufrufen. Stattdessen können Sie die folgenden Befehle verwenden:

$ s=/the/path/foo.txt
$ echo ${s##*/}
foo.txt
$ s=${s##*/}
$ echo ${s%.txt}
foo
$ echo ${s%.*}
foo

Beachten Sie, dass diese Lösung in allen neueren ( nach 2004 ) POSIX konforme Shells (z. B. bash, dash, ksh usw.).

Quelle: Shell Command Language 2.6.2 Parametererweiterung

Weitere Informationen zu Bash-String-Manipulationen: http://tldp.org/LDP/LG/issue18/bash.html

575
ghostdog74

Der Basisname Befehl hat zwei verschiedene Aufrufe; In einem geben Sie nur den Pfad an. In diesem Fall erhalten Sie die letzte Komponente. In dem anderen geben Sie auch ein Suffix an, das entfernt wird. Sie können Ihren Beispielcode also vereinfachen, indem Sie den zweiten Aufruf von basename verwenden. Achten Sie auch darauf, die Dinge richtig zu zitieren:

 fbname = $ (Basisname "$ 1" .txt) 
 Echo "$ fbname" 
263

Eine Kombination aus Basisname und Schnitt funktioniert auch bei einer doppelten Endung wie .tar.gz einwandfrei:

fbname=$(basename "$fullfile" | cut -d. -f1)

Wäre interessant, wenn diese Lösung weniger Rechenleistung benötigt als die Bash-Parameter-Erweiterung.

54
kom lim

Pure bash, keine basename, keine variable Jonglage. Setze einen String und echo:

s=/the/path/foo.txt
echo ${s//+(*\/|.*)}

Ausgabe:

foo

Hinweis: Die Option bash extglob muss aktiviert sein. ( Ubuntu setzt extglob "on" (standardmäßig aktiviert), wenn dies nicht der Fall ist, führen Sie Folgendes aus:

shopt -s extglob

Durch das ${s//+(*\/|.*)} gehen:

  1. ${s - Beginnen Sie mit $ s .
  2. // Ersetzen Sie jede Instanz des Musters.
  3. +( stimmt mit einem oder mehreren der Musterliste in Klammern überein, ( dh bis Punkt 7 unten).
  4. 1. Muster: *\/ stimmt mit etwas vor einem Literalzeichen "/" überein.
  5. mustertrennzeichen |, das in diesem Fall wie ein logisches ODER wirkt.
  6. 2. Muster: .* stimmt mit etwas nach einem Literal "." überein - dh in bash das ". "ist nur ein Punkt und nicht ein regulärer Punkt .
  7. ) Musterliste beenden .
  8. } Parametererweiterung beenden. Bei einer Zeichenfolgensubstitution gibt es normalerweise einen anderen /, gefolgt von einer Ersatzzeichenfolge. Da dort jedoch kein / vorhanden ist, werden die übereinstimmenden Muster durch nichts ersetzt. Dadurch werden die Übereinstimmungen gelöscht.

Relevanter man bash Hintergrund:

  1. Mustersubstitution :
  ${parameter/pattern/string}
          Pattern substitution.  The pattern is expanded to produce a pat‐
          tern just as in pathname expansion.  Parameter is  expanded  and
          the  longest match of pattern against its value is replaced with
          string.  If pattern begins with /, all matches  of  pattern  are
          replaced   with  string.   Normally  only  the  first  match  is
          replaced.  If pattern begins with #, it must match at the begin‐
          ning of the expanded value of parameter.  If pattern begins with
          %, it must match at the end of the expanded value of  parameter.
          If string is null, matches of pattern are deleted and the / fol‐
          lowing pattern may be omitted.  If parameter is @ or *, the sub‐
          stitution  operation  is applied to each positional parameter in
          turn, and the expansion is the resultant list.  If parameter  is
          an  array  variable  subscripted  with  @ or *, the substitution
          operation is applied to each member of the array  in  turn,  and
          the expansion is the resultant list.
  1. Erweiterte Mustererkennung :
  If the extglob Shell option is enabled using the shopt builtin, several
   extended  pattern  matching operators are recognized.  In the following
   description, a pattern-list is a list of one or more patterns separated
   by a |.  Composite patterns may be formed using one or more of the fol‐
   lowing sub-patterns:

          ?(pattern-list)
                 Matches zero or one occurrence of the given patterns
          *(pattern-list)
                 Matches zero or more occurrences of the given patterns
          +(pattern-list)
                 Matches one or more occurrences of the given patterns
          @(pattern-list)
                 Matches one of the given patterns
          !(pattern-list)
                 Matches anything except one of the given patterns
18
agc

Hier sind Oneliner:

  1. $(basename ${s%.*})
  2. $(basename ${s} .${s##*.})

Ich brauchte das, genauso wie ich es von bongbang und w4etwetewtwet gefragt habe.

15
sancho.s

Hier ist eine andere (komplexere) Möglichkeit, den Dateinamen oder die Erweiterung abzurufen: Verwenden Sie zuerst den Befehl rev, um den Dateipfad umzukehren, schneiden Sie den ersten . aus und kehren Sie dann den Dateipfad erneut um :

filename=`rev <<< "$1" | cut -d"." -f2- | rev`
fileext=`rev <<< "$1" | cut -d"." -f1 | rev`
9
higuaro

Wenn Sie Nice mit Windows-Dateipfaden (unter Cygwin) spielen möchten, können Sie dies auch versuchen:

fname=${fullfile##*[/|\\]}

Dies wird bei Verwendung von BaSH unter Windows die Backslash-Trennzeichen berücksichtigen.

2
Apelsin

Nur eine Alternative, die ich mir ausgedacht habe, um eine Erweiterung zu extrahieren, indem ich die Beiträge in diesem Thread mit meiner eigenen kleinen Wissensbasis verwendet habe, die mir vertrauter war.

ext="$(rev <<< "$(cut -f "1" -d "." <<< "$(rev <<< "file.docx")")")"

Hinweis: Bitte informieren Sie mich über die Verwendung von Anführungszeichen. Es hat bei mir funktioniert, aber mir fehlt möglicherweise etwas bei der richtigen Verwendung (ich verwende wahrscheinlich zu viele).

0
Diomoid