Come rimuovo il suffisso del file e la porzione di percorso da una stringa di percorso in Bash?

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

  •  02-07-2019
  •  | 
  •  

Domanda

Dato un percorso del file di stringa come /foo/fizzbuzz.bar , come userei bash per estrarre solo la parte fizzbuzz di detta stringa?

È stato utile?

Soluzione

Ecco come farlo con gli operatori # e% in Bash.

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

$ {x% .bar} potrebbe anche essere $ {x%. *} per rimuovere tutto dopo un punto o $ {x %%. *} per rimuovere tutto dopo il primo punto.

Esempio:

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

La documentazione è disponibile nel Manuale di Bash . Cerca $ {parametro% word} e $ {parameter %% word} sezione di corrispondenza della porzione finale.

Altri suggerimenti

guarda il comando basename:

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

Puro bash, fatto in due operazioni separate:

  1. Rimuovi il percorso da una stringa di percorso:

    path=/foo/bar/bim/baz/file.gif
    
    file=${path##*/}  
    #$file is now 'file.gif'
    
  2. Rimuovi l'estensione da una stringa di percorso:

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

Usando il nome di base ho usato quanto segue per raggiungere questo obiettivo:

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

    # Do things with $fname
done;

Questo non richiede alcuna conoscenza a priori dell'estensione del file e funziona anche quando hai un nome file che ha punti nel suo nome file (davanti alla sua estensione); richiede però il programma basename , ma fa parte dei coreutils GNU, quindi dovrebbe essere distribuito con qualsiasi distro.

Pure bash way:

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

Questa funzionalità è spiegata da man bash in " Parameter Expansion " ;. I modi non bash abbondano: awk, perl, sed e così via.

EDIT: funziona con i punti nel file suffissi e non è necessario conoscere il suffisso (estensione), ma non funziona #em # 8217; t funziona con i punti nel < em> nome stesso.

Le funzioni basname e dirname sono ciò che stai cercando:

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

Ha un output:

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

L'uso di basename presuppone che tu sappia qual è l'estensione del file, vero?

E credo che i vari suggerimenti di espressioni regolari non facciano fronte a un nome di file contenente più di un "quotato".

Quanto segue sembra far fronte a punti doppi. Oh, e nomi di file che contengono un " / " stessi (solo per i calci)

Per parafrasare Pascal, " Siamo spiacenti, questo script è così lungo. Non ho avuto il tempo di accorciarlo "


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

Se non puoi usare il nome di base come suggerito in altri post, puoi sempre usare sed. Ecco un (brutto) esempio. Non è il massimo, ma funziona estraendo la stringa desiderata e sostituendo l'input con la stringa desiderata.

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

Quale ti darà l'output

  
    

FizzBuzz

  

Oltre alla sintassi conforme POSIX utilizzata in questa risposta ,

basename string [suffix]

come in

basename /foo/fizzbuzz.bar .bar

GNU basename supporta un'altra sintassi:

basename -s .bar /foo/fizzbuzz.bar

con lo stesso risultato. La differenza e il vantaggio è che -s implica -a , che supporta più argomenti:

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

Questo può anche essere reso sicuro da nome file separando l'output con byte NUL usando l'opzione -z , ad esempio per questi file contenenti spazi vuoti, newline e caratteri glob (citati da ls ):

$ ls has*
'has'

Lettura in un array:

$ readarray -d 

readarray -d richiede Bash 4.4 o versioni successive. Per le versioni precedenti, dobbiamo eseguire il ciclo:

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

Lettura in un array:

<*>

readarray -d richiede Bash 4.4 o versioni successive. Per le versioni precedenti, dobbiamo eseguire il ciclo:

<*>\0' arr < <(basename -zs .bar has*) $ declare -p arr declare -a arr=([0]=

readarray -d richiede Bash 4.4 o versioni successive. Per le versioni precedenti, dobbiamo eseguire il ciclo:

<*>\n''newline.bar' 'has space.bar' 'has*.bar'

Lettura in un array:

<*>

readarray -d richiede Bash 4.4 o versioni successive. Per le versioni precedenti, dobbiamo eseguire il ciclo:

<*>has\nnewline' [1]="has space" [2]="has*")

readarray -d richiede Bash 4.4 o versioni successive. Per le versioni precedenti, dobbiamo eseguire il ciclo:

<*>\n''newline.bar' 'has space.bar' 'has*.bar'

Lettura in un array:

<*>

readarray -d richiede Bash 4.4 o versioni successive. Per le versioni precedenti, dobbiamo eseguire il ciclo:

<*>

Attenzione alla soluzione perl suggerita: rimuove qualsiasi cosa dopo il primo punto.

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

Se vuoi farlo con perl, questo funziona:

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

Ma se stai usando Bash, le soluzioni con y = $ {x%. *} (o basename " $ x " .ext se conosci il estensione) sono molto più semplici.

Il basename lo fa, rimuove il percorso. Rimuoverà anche il suffisso se fornito e se corrisponde al suffisso del file ma sarà necessario conoscere il suffisso da dare al comando. Altrimenti puoi usare mv e capire quale dovrebbe essere il nuovo nome in qualche altro modo.

Combinazione della risposta più votata con la seconda risposta più votata per ottenere il nome file senza il percorso completo:

$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top