Получите только имя файла из пути в Bash script

Как получить только имя файла без расширения и без пути?

Следующее не дает мне расширения, но у меня все еще есть путь:

source_file_filename_no_ext=${source_file%.*}

Ответ 1

Большинство UNIX-подобных операционных систем имеют исполняемый файл basename для очень сходной цели (и dirname для пути):

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

Это, к сожалению, просто дает вам имя файла, включая расширение, поэтому вам также нужно найти способ снять это.

Итак, учитывая, что вам все равно нужно это сделать, вы также можете найти метод, который может удалить путь и расширение.

Один из способов сделать это (и это решение 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 (расширение файла).

Ответ 2

Вот простой способ получить имя файла из пути:

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

Чтобы удалить расширение, которое вы можете использовать, если имя файла имеет только ОДНУЮ точку (добавочную точку):

cut -d"." -f1

Ответ 3

basename и dirname более удобны. Это альтернативные команды:

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

Это возвращает test.old.img как basename.

Это имя файла солей без расширения:

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

Он возвращает test.old.

И следующая инструкция дает полный путь, как команда dirname.

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

Возвращает /opt/datastores/sda2

Ответ 4

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

Ответ 5

Несколько альтернативных вариантов, потому что регулярные выражения (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, даже если имя файла имеет несколько "." s в нем. Он также может обрабатывать пробелы в пути к файлу и если путь к файлу встроен или завернут в строку.

#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, вы можете начать с этого:

 [^\\]*$       

Ответ 6

$ file=${$(basename $file_path)%.*}