Risposte:
basename
dai coreutils GNU può aiutarti a fare questo lavoro:
$ basename /root/video.mp4
video.mp4
Se conosci già l'estensione del file, puoi richiamare basename
usando la sintassi basename NAME [SUFFIX]
per rimuoverlo:
$ basename /root/video.mp4 .mp4
video
Oppure un'altra opzione sarebbe tagliare tutto dopo l'ultimo punto usando sed
:
$ basename /root/video.old.mp4 | sed 's/\.[^.]*$//'
video.old
La soluzione più semplice è rimuovere tutto fino all'ultima comparsa di /
:
echo /root/video.mp4 | sed 's/.*\///'
Utilizzare uno dei seguenti modi:
out_file="${in_file##*/}"
out_file="$(basename $in_file)"
out_file="$(echo $in_file | sed 's=.*/==')"
out_file="$(echo $in_file | awk -F"/" '{ print $NF }')"
ps. Ottieni la stessa stringa perché nell'istruzione \(.*\.\)
corrisponde alla stringa dall'inizio fino al punto ( /root/video.
) e quindi aggiungi manualmente .mp4
quale è la stessa della stringa originale. Dovresti usare s=.*\([^/]*\)=\1=
invece.
Aggiornamento: (il primo è stato risolto ora)
Per ottenere l'unico nome file senza estensione puoi:
out_file="$(echo $in_file | sed 's=.*/==;s/\.[^.]*$/.new_ext/')"
out_file="$(echo $in_file | sed 's=\([^/]*\)\.[^./]*$=\1.new_ext=')"
out_file="$(echo $in_file | awk -F"/" '{ gsub (/\.[^/.]*$/,".new_ext",$NF);print $NF }'
my.file.tar.gz
.
sed
e awk
. Fisso. Grazie.
Uno dei fondamenti dell'uso di regex è che i modelli sono avidi per natura quando si specifica il jolly. Mentre la risposta proposta da @uloBasEI è sicuramente una risposta funzionante, richiede anche l'uso del comando basename. La domanda originale di @Shixons richiede una soluzione usando solo sed.
Prima di continuare, è sempre utile sapere quale versione di sed è l'obiettivo. Sto assumendo BSD (come fornito con OSX).
Prima di tutto, il modello proposto nella domanda originale non funziona perché cattura tutto dall'inizio della stringa di input fino all'ultimo punto incluso. Senza ancore, questa ricerca inghiottirà tutto da sinistra a destra. Il modello corrispondente "/ 1", quindi, è tutto fino all'ultimo punto incluso. Anche un nome di file con più punti verrà inghiottito intero. Non è il risultato desiderato affatto.
Il primo passo è stabilire una strategia per identificare i modelli. Qui, ti piacerebbe sbarazzarti di tutto a sinistra del nome del file (ci occuperemo dell'estensione in seguito):
out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"
La ricerca corrisponde dall'inizio della stringa. Abbina uno schema di "/.*" zero o più volte ed elimina tutto in seguito. Stampiamo i motivi abbinati con "\ 1". Non stiamo cercando a livello globale; stiamo cercando dall'inizio della stringa specificando l'ancora ^.
Otteniamo maggiore chiarezza abilitando l'opzione "-E" in modo da non dover sfuggire alle parentesi:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"
Quindi ora abbiamo la parte a sinistra. Aggiungiamo la parte a destra. Nota che dobbiamo mantenere la parte sinistra come modello perché è così che possiamo specificare che appare zero o più volte. Tutto ciò che facciamo ora è aggiungere un modello per la parte a destra:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"
Stampiamo solo la seconda corrispondenza, scartando così tutto tranne il nome file. Ma dobbiamo ancora rimuovere l'estensione del nome file.
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"
"$" Alla fine è facoltativo.
Infine, per aggiungere la nuova estensione basta rivedere in questo modo:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"
Un'ulteriore ottimizzazione è rendere facoltativa la prima barra diretta per gestire i percorsi relativi:
out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"
Mi sono imbattuto in questa domanda essendo pigro mentre cercavo un modello sed per sostituire il nome di base . Sto lavorando su un sistema privato che non ha quel comando installato.
sed 's/\.[^.]*$//'
come hai, fallirà per (nascosto).filename
e.
per le..
directory