2010-07-29 21 views

Respuesta

461

mayoría UNIX tienen un ejecutable basename para un propósito muy similar (y dirname para la ruta):

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

que, lamentablemente, sólo le da el nombre de archivo, incluyendo la extensión, por lo que había necesidad de encontrar una manera de despojar de que fuera así.

Por lo tanto, dado que tiene que hacer eso de todos modos, también puede encontrar un método que puede quitar la ruta y la extensión.

Una manera de hacer eso (y esto es una solución -sólo bash, sin necesidad de otros ejecutables):

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 

Ese pequeño fragmento establece xpath (la ruta del archivo), xpref (el prefijo del archivo, lo estaba solicitando específicamente) y xfext (la extensión del archivo).

+0

Sé que hay algo que ver con bash como el anterior. Simplemente no sé cuál es la palabra clave. Me gustaría obtener la ruta de acceso, el nombre de archivo y la extensión separados en diferentes variables. – Keith

+0

Si desea obtener el camino: path = $ (echo $ filename | sed-e 's/\/[^ \ /] * $/\ //') Si desea obtener la extensión: ext = $ (echo $ filename | sed-e 's /[^\.]*\.//') – jcubic

+3

@Keith: para pathname, use 'path = $ (dirname $ filename)'; no hay un comando para darle la extensión per se, pero @paxdiablo le mostró cómo el shell puede hacerlo. –

10
$ source_file_filename_no_ext=${source_file%.*} 
$ echo ${source_file_filename_no_ext##*/} 
+0

Solo obtengo una comodín con la extensión usando esto. – Kebman

18

Aquí es una manera fácil de obtener el nombre de archivo de una ruta:

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

Para eliminar la extensión se puede utilizar, asumiendo el nombre de archivo tiene un solo punto (el punto de extensión):

cut -d"." -f1 
+7

No es una buena suposición, y hay herramientas y comandos diseñados específicamente para hacer esto correctamente. – Tony

+0

Además, no recomendaría usar el nombre de variable 'PATH', ya que esto puede entrar en conflicto con la variable' PATH' del sistema – Tabea

19

basename y dirname soluciones son más convenientes. Esos son los comandos alternativos:

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

Esto devuelve test.old.img como basename.

Este es el nombre de archivo sin la extensión de sal:

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

Devuelve test.old.

Y la instrucción siguiente da la ruta completa como dirname comando.

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

Devuelve /opt/datastores/sda2

+0

cool, ¿y si hay parámetros? –

6

Algunas opciones alternativas más debido expresiones regulares (regi?) Son impresionantes!

Aquí es una expresión regular simple para hacer el trabajo:

regex="[^/]*$" 

Ejemplo (grep):

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

Ejemplo (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 necesita una expresión regular más complicada: Por ejemplo, su ruta está envuelta en una cadena.

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 

solución total con expresiones regulares:

Esta función le puede dar el nombre de archivo con o sin extensión de una ruta de archivo de Linux, incluso si el nombre del archivo tiene múltiples s en ella "". También puede manejar espacios en la ruta de archivo y si la ruta del archivo está incrustada o envuelta en una cadena.

#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 usted tiene que meterse con un camino de ventanas se puede comenzar con éste:

[^\\]*$  
5
$ file=${$(basename $file_path)%.*} 
+0

Esto devuelve "mala sustitución" en bash v4.4.7. Creo que la solución sed de Fırat KÜÇÜK es mejor, es decir, $ (basename $ the_file_path) | sed "s /\..*//" – Marshal

+0

Quise decir 'echo $ (basename $ the_file_path) | sed "s /\..*//" ' – Marshal

Cuestiones relacionadas