2010-07-29 17 views

Odpowiedz

461

Większość uniksopodobnego systemy operacyjne mają basename wykonywalny na bardzo podobnym celu (i dirname dla ścieżki):

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

to niestety tylko daje nazwę pliku, tym rozszerzeniem, więc trzeba by znaleźć sposób na pasek, który także wyłączyć.

Tak więc, biorąc pod uwagę, że i tak musicie to zrobić, równie dobrze można znaleźć metodę, która może zedrzeć ze ścieżki i rozszerzenie.

Jednym ze sposobów, aby to zrobić (i jest to bash rozwiązanie -Tylko, potrzebując żadnych innych plików wykonywalnych):

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 

Ten mały fragment Zestawy xpath (ścieżka pliku), xpref (prefiks pliku, co o co prosiliście) i xfext (rozszerzenie pliku).

+0

Wiem, że jest coś wspólnego z bash, jak wyżej. Po prostu nie wiem, jakie jest kluczowe słowo. Chciałbym uzyskać nazwę ścieżki, nazwę pliku i rozszerzenie podzielone na różne zmienne. – Keith

+0

Jeśli chcesz uzyskać ścieżkę, użyj: ścieżka = $ (echo $ nazwa pliku | sed -e 's/\/[^ \ /] * $/\ //') Jeśli chcesz uzyskać rozszerzenie: ext = $ (echo $ filename | sed -e 's /[ ^\ .]*\ .//') – jcubic

+3

@Keith: dla ścieżki, użyj 'path = $ (dirname $ filename)'; nie ma polecenia, by dać ci rozszerzenie jako takie, ale @paxdiablo pokazało ci, jak może to zrobić powłoka. –

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

Mam tylko wildcard z rozszerzeniem używającym tego. – Kebman

18

Oto prosty sposób, aby uzyskać nazwę pliku ze ścieżki:

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

Aby usunąć rozszerzenie można wykorzystać, zakładając, że nazwa pliku ma tylko jeden punkt (kropka rozszerzenie):

cut -d"." -f1 
+7

To nie jest dobre założenie, a istnieją narzędzia i polecenia specjalnie zaprojektowane, aby zrobić to poprawnie. – Tony

+0

Ponadto, nie polecam używania nazwy zmiennej 'PATH', ponieważ może to kolidować ze zmienną' PATH' systemu – Tabea

19

basename i dirname rozwiązania są bardziej wygodne. Są alternatywne komendy:

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

ta zwraca test.old.img jak basename.

To sól nazwa pliku bez rozszerzenia:

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

Zwraca test.old.

Następująca instrukcja podaje pełną ścieżkę, na przykład polecenie dirname.

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

Zwraca /opt/datastores/sda2

+0

fajnie, a co jeśli są parametry? –

6

Niektóre bardziej alternatywnych opcji ponieważ Wyrażenia regularne (regi?) Są niesamowite!

Oto prosty regex do pracy:

regex="[^/]*$" 

Przykład (grep):

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

Przykład (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 

Jeśli potrzebujesz bardziej skomplikowanego wyrażenia regularnego: Na przykład twoja ścieżka jest zawijana w ciąg.

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 

całkowita rozwiązanie z regexes:

Ta funkcja może dać nazwę pliku z lub bez przedłużenia filePath linux nawet jeśli nazwa pliku ma wiele s w nim „”. Może również obsługiwać spacje w ścieżce do pliku i jeśli ścieżka do pliku jest osadzona lub zawinięta w łańcuch.

#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" 

Jeśli masz bałagan ze ścieżką okien można zacząć od tego:

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

To zwraca "złe zastąpienie" w bash v4.4.7. Myślę, że rozwiązanie sed Fırat KÜÇÜK jest lepsze, tj. $ (Basename $ the_file_path) | sed "s/\..*//" – Marshal

+0

Miałem na myśli 'echo $ (basename $ the_file_path) | sed "s /\..*//" ' – Marshal

Powiązane problemy