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

228

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

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

source_file_filename_no_ext=${source_file%.*}
  • 10
    echo $(basename "${filepath%.*}")
  • 0
    $ (базовое имя -a -s .ext /path/to/file.ext)
Теги:
scripting

6 ответов

425

Большинство 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 (расширение файла).

  • 0
    Я знаю, что есть что-то общее с bash, как описано выше. Я просто не знаю, какое ключевое слово. Я хотел бы получить путь, имя файла и расширение разделить на разные переменные.
  • 0
    Если вы хотите получить путь, используйте: path = $ (echo $ filename | sed -e 's / \ / [^ \ /] * $ / \ //') Если вы хотите получить расширение: ext = $ (echo $ имя файла | sed -e 's /[^\.]*\.//')
Показать ещё 15 комментариев
18

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

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

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

cut -d"." -f1
  • 7
    Это неверное предположение, и существуют инструменты и команды, специально предназначенные для этого.
  • 1
    Кроме того, я бы не рекомендовал использовать имя PATH , поскольку это может конфликтовать с системной переменной PATH
14

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

  • 0
    круто, что если есть параметры?
10
$ source_file_filename_no_ext=${source_file%.*}
$ echo ${source_file_filename_no_ext##*/}
  • 0
    Я получаю только подстановочный знак с расширением, используя это.
6

Несколько альтернативных вариантов, потому что регулярные выражения (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, вы можете начать с этого:

 [^\\]*$       
3
$ file=${$(basename $file_path)%.*}
  • 2
    Это возвращает «плохую замену» в bash v4.4.7. Я думаю, что решение sed Fırat KÜÇÜK лучше, то есть $ (basename $ the_file_path) | sed "s /\..*//"
  • 1
    Я имел в виду echo $(basename $the_file_path) | sed "s/\..*//"

Ещё вопросы

Сообщество Overcoder
Наверх
Меню