web-dev-qa-db-ja.com

Bashスクリプトのパスからファイル名だけを取得する

拡張子とパスのないファイル名だけを取得するにはどうすればよいですか。

次の例では拡張子はありませんが、それでもパスは添付されています。

source_file_filename_no_ext=${source_file%.*}
321
Keith

ほとんどのUNIX系オペレーティングシステムには、非常によく似た目的のためにbasename実行可能ファイルがあります(パスにはdirname)。

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

残念ながら、という拡張子を付けてファイル名を指定するだけなので、それを取り除く方法も見つける必要があります。

それで、あなたがとにかくそれをしなければならないならば、パス拡張子を取り除くことができるメソッドを見つけることができるかもしれません。

そのための1つの方法があります(これはbash-onlyソリューションであり、他の実行可能ファイルは必要ありません)。

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

その小さな断片は、xpath(ファイルパス)、xpref(ファイルプレフィックス、あなたが特に求めていたもの)そしてxfext(ファイル拡張子)を設定します。

587
paxdiablo

basenamedirnameの解決策がより便利です。これらは代替コマンドです:

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

これはbasenameのようにtest.old.imgを返します。

これは拡張子のないsaltファイル名です。

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

test.oldを返します。

そして、次のステートメントはdirnameコマンドのようなフルパスを与えます。

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

/opt/datastores/sda2を返します

41
Fırat KÜÇÜK

これはパスからファイル名を取得する簡単な方法です:

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

ファイル名にドットが1つしかない(拡張子ドット)と仮定して、使用できる拡張子を削除します。

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

正規表現(regi?)がすごいので、もう少し選択肢があります!

これは仕事をするための単純な正規表現です:

 regex="[^/]*$"

例(grep):

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

例(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

より複雑な正規表現が必要な場合:たとえば、パスは文字列で囲まれています。

 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

正規表現によるトータルソリューション:

この関数は、ファイル名に複数の "。"が含まれていても、Linuxファイルパスの拡張子の有無にかかわらず、ファイル名を指定できます。ファイルパス内のスペースや、ファイルパスが埋め込まれている場合や文字列で囲まれている場合も処理できます。

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

あなたがwindowsのパスをいじらなければならないなら、あなたはこれで始めることができます:

 [^\\]*$       
8
jkdba