Comment obtenir uniquement un nom de fichier en utilisant sed

17

Comment puis-je obtenir uniquement le nom de fichier en utilisant sed? J'ai ça

out_file=$(echo $in_file|sed "s/\(.*\.\).*/\1mp4/g")

Mais j'ai aussi le chemin /root/video.mp4et je veux seulement video.mp4.

Shixons
la source

Réponses:

26

basenamede GNU coreutils peut vous aider à faire ce travail:

$ basename /root/video.mp4
video.mp4

Si vous connaissez déjà l'extension du fichier, vous pouvez invoquer en basenameutilisant la syntaxe basename NAME [SUFFIX]pour la supprimer:

$ basename /root/video.mp4 .mp4
video

Ou une autre option serait de tout couper après le dernier point en utilisant sed:

$ basename /root/video.old.mp4 | sed 's/\.[^.]*$//'
video.old
uloBasEI
la source
3
L'utilisation sed 's/\.[^.]*$//'comme vous l'avez fait, échouera pour (caché) .filenameet .et les ..répertoires
Peter.O
9

La solution la plus simple est de tout supprimer jusqu'à la dernière apparition de /:

echo /root/video.mp4 | sed 's/.*\///'

Marguerite
la source
5

Utilisez l'une des méthodes suivantes:

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. Vous obtenez la même chaîne, car dans votre instruction \(.*\.\)correspond à la chaîne depuis le début jusqu'à dot ( /root/video.), puis vous ajoutez manuellement.mp4 ce qui est le même que dans votre chaîne d'origine. Vous devriez utiliser à la s=.*\([^/]*\)=\1=place.

Mise à jour: (la première est corrigée maintenant)

Pour obtenir le seul nom de fichier sans extension, vous pouvez:

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 }'
se ruer
la source
Mais avec l'une de ces méthodes, j'obtiens le nom de fichier avec le format et je dois obtenir uniquement le nom de fichier et mettre un nouveau format manuellement.
Shixons
Ah, ça a du sens. J'ai mis à jour ma réponse.
précipiter
@rush: Il y aura des cas marginaux, par exemple pour un fichier nommé my.file.tar.gz.
donothingsuccessfully
@donothingsuccessfully il y avait un symbole de point manquant dans le dernier sedet awk. Fixé. Je vous remercie.
précipiter
4

L'un des principes fondamentaux de l'utilisation de l'expression régulière est que les modèles sont gourmands par nature lors de la spécification du caractère générique. Bien que la réponse proposée par @uloBasEI soit certainement une réponse fonctionnelle, elle nécessite également l'utilisation de la commande basename. La question d'origine de @Shixons demande une solution utilisant uniquement sed.

Avant de continuer, il est toujours utile de savoir quelle version de sed est la cible. Je suppose BSD (tel que livré avec OSX).

Tout d'abord, le modèle proposé dans la question d'origine ne fonctionne pas car il capture tout depuis le début de la chaîne d'entrée jusqu'au dernier point inclus. Sans ancres, cette recherche engloutira tout de gauche à droite. Le motif apparié "/ 1", par conséquent, est tout jusqu'au dernier point inclus. Même un nom de fichier avec plusieurs points sera englouti en entier. Pas du tout le résultat souhaité.

La première étape consiste à établir une stratégie d'identification des modèles. Ici, vous souhaitez vous débarrasser de tout à gauche du nom de fichier (nous traiterons de l'extension plus tard):

out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"

La recherche correspond au début de la chaîne. Il correspond à un modèle de "/.*" zéro ou plusieurs fois et supprime tout par la suite. Nous imprimons les motifs assortis avec "\ 1". Nous ne cherchons pas globalement; nous recherchons depuis le début de la chaîne en spécifiant l'ancre ^.

Nous obtenons une meilleure clarté en activant l'option "-E" afin que nous n'ayons pas à échapper les parenthèses:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"

Nous avons donc maintenant la partie à gauche. Ajoutons la partie à droite. Notez que nous devons conserver la partie gauche en tant que motif, car c'est ainsi que nous pouvons spécifier qu'elle apparaît zéro ou plusieurs fois. Tout ce que nous faisons maintenant est d'ajouter un motif pour la pièce de droite:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"

Nous imprimons uniquement la deuxième correspondance, éliminant ainsi tout sauf le nom de fichier. Mais nous devons toujours supprimer l'extension du nom de fichier.

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"

Le "$" à la fin est facultatif.

Enfin, pour ajouter la nouvelle extension que vous venez de réviser comme suit:

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"

Une optimisation supplémentaire consiste à rendre la première barre oblique facultative pour gérer les chemins relatifs:

out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"

Je suis tombé sur cette question en étant paresseux en cherchant un motif sed pour remplacer le nom de base . Je travaille sur un système dépouillé sur lequel cette commande n'est pas installée.

markeissler
la source