it-swarm.com.ru

Получить только имя файла из пути в скрипте 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

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

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

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

Решения 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

41
Fırat KÜÇÜK

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

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

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

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