web-dev-qa-db-fra.com

Obtenir uniquement le nom de fichier d'un chemin d'accès dans un script Bash

Comment pourrais-je obtenir juste le nom de fichier sans l'extension et sans chemin?

Ce qui suit ne me donne aucune extension, mais j'ai toujours le chemin attaché:

source_file_filename_no_ext=${source_file%.*}
330
Keith

La plupart des systèmes d'exploitation de type UNIX ont un exécutable basename dans un but très similaire (et dirname pour le chemin):

pax> a=/tmp/file.txt
pax> b=$(basename $a)
pax> echo $b
file.txt

Malheureusement, cela ne vous donne que le nom du fichier, y compris l'extension, vous devez donc trouver un moyen de le supprimer également.

Donc, étant donné que vous devez le faire de toute façon, vous pouvez aussi bien trouver une méthode qui peut effacer le chemin et l'extension.

Une façon de le faire (et ceci est une solution bash- uniquement, ne nécessitant aucun autre exécutable):

pax> a=/tmp/xx/file.tar.gz
pax> xpath=${a%/*} 
pax> xbase=${a##*/}
pax> xfext=${xbase##*.}
pax> xpref=${xbase%.*}
pax> echo;echo path=${xpath};echo pref=${xpref};echo ext=${xfext}

path=/tmp/xx
pref=file.tar
ext=gz

Ce petit extrait définit xpath (le chemin du fichier), xpref (le préfixe du fichier, ce que vous demandiez spécifiquement) et xfext (l'extension du fichier).

605
paxdiablo

Les solutions basename et dirname sont plus pratiques. Ce sont des commandes alternatives:

FILE_PATH="/opt/datastores/sda2/test.old.img"
echo "$FILE_PATH" | sed "s/.*\///"

Ceci retourne test.old.img comme basename.

C'est un nom de fichier sel sans extension:

echo "$FILE_PATH" | sed -r "s/.+\/(.+)\..+/\1/"

Il retourne test.old.

Et l'instruction suivante donne le chemin complet comme la commande dirname.

echo "$FILE_PATH" | sed -r "s/(.+)\/.+/\1/"

Il retourne /opt/datastores/sda2

44
Fırat KÜÇÜK

Voici un moyen simple d’obtenir le nom du fichier à partir d’un chemin:

echo "$PATH" | rev | cut -d"/" -f1 | rev

Pour supprimer l’extension que vous pouvez utiliser, en supposant que le nom du fichier ne comporte qu’UN point (le point de l’extension):

cut -d"." -f1
23
Ivry345
$ source_file_filename_no_ext=${source_file%.*}
$ echo ${source_file_filename_no_ext##*/}
12
ghostdog74
$ file=${$(basename $file_path)%.*}
12
mihai

Quelques options plus alternatives parce que les expressions régulières (regi?) Sont géniales!

Voici un regex simple pour faire le travail:

 regex="[^/]*$"

Exemple (grep):

 FP="/hello/world/my/file/path/hello_my_filename.log"
 echo $FP | grep -oP "$regex"
 #Or using standard input
 grep -oP "$regex" <<< $FP

Exemple (awk):

 echo $FP | awk '{match($1, "$regex",a)}END{print a[0]}
 #Or using stardard input
 awk '{match($1, "$regex",a)}END{print a[0]} <<< $FP

Si vous avez besoin d'un regex plus compliqué: Par exemple, votre chemin est encapsulé dans une chaîne.

 StrFP="my string is awesome file: /hello/world/my/file/path/hello_my_filename.log sweet path bro."

 #this regex matches a string not containing / and ends with a period 
 #then at least one Word character 
 #so its useful if you have an extension

 regex="[^/]*\.\w{1,}"

 #usage
 grep -oP "$regex" <<< $StrFP

 #alternatively you can get a little more complicated and use lookarounds
 #this regex matches a part of a string that starts with /  that does not contain a / 
 ##then uses the lazy operator ? to match any character at any amount (as little as possible hence the lazy)
 ##that is followed by a space
 ##this allows use to match just a file name in a string with a file path if it has an exntension or not
 ##also if the path doesnt have file it will match the last directory in the file path 
 ##however this will break if the file path has a space in it.

 regex="(?<=/)[^/]*?(?=\s)"

 #to fix the above problem you can use sed to remove spaces from the file path only
 ## as a side note unfortunately sed has limited regex capibility and it must be written out in long hand.
 NewStrFP=$(echo $StrFP | sed 's:\(/[a-z]*\)\( \)\([a-z]*/\):\1\3:g')
 grep -oP "$regex" <<< $NewStrFP

Solution totale avec Regexes:

Cette fonction peut vous donner le nom de fichier avec ou sans extension d’un chemin de fichier Linux même si le nom de fichier contient plusieurs "." Il peut également gérer des espaces dans le chemin du fichier et si le chemin du fichier est incorporé ou encapsulé dans une chaîne.

#you may notice that the sed replace has gotten really crazy looking
#I just added all of the allowed characters in a linux file path
function Get-FileName(){
    local FileString="$1"
    local NoExtension="$2"
    local FileString=$(echo $FileString | sed 's:\(/[a-zA-Z0-9\<\>\|\\\:\)\(\&\;\,\?\*]*\)\( \)\([a-zA-Z0-9\<\>\|\\\:\)\(\&\;\,\?\*]*/\):\1\3:g')

    local regex="(?<=/)[^/]*?(?=\s)"

    local FileName=$(echo $FileString | grep -oP "$regex")

    if [[ "$NoExtension" != "" ]]; then
        sed 's:\.[^\.]*$::g' <<< $FileName
    else
        echo "$FileName"
    fi
}

## call the function with extension
Get-FileName "my string is awesome file: /hel lo/world/my/file test/path/hello_my_filename.log sweet path bro."

##call function without extension
Get-FileName "my string is awesome file: /hel lo/world/my/file test/path/hello_my_filename.log sweet path bro." "1"

Si vous devez jouer avec un chemin Windows, vous pouvez commencer par celui-ci:

 [^\\]*$       
8
jkdba