Linux script file name

Get just the filename from a path in a Bash script [duplicate]

How would I get just the filename without the extension and no path? The following gives me no extension, but I still have the path attached:

source_file_filename_no_ext=$

6 Answers 6

Many UNIX-like operating systems have a basename executable for a very similar purpose (and dirname for the path):

pax> full_name=/tmp/file.txt pax> base_name=$(basename $) pax> echo $ file.txt 

That unfortunately just gives you the file name, including the extension, so you’d need to find a way to strip that off as well.

So, given you have to do that anyway, you may as well find a method that can strip off the path and the extension.

One way to do that (and this is a bash -only solution, needing no other executables):

pax> full_name=/tmp/xx/file.tar.gz pax> xpath=$ pax> xbase=$ pax> xfext=$ pax> xpref=$ pax> echo "path='$', pref='$', ext='$'" path='/tmp/xx', pref='file.tar', ext='gz' 

That little snippet sets xpath (the file path), xpref (the file prefix, what you were specifically asking for) and xfext (the file extension).

I know there is something to do with bash like the above. I just don’t know what the key word is. I would like to get get the pathname, filename, and extension separated into different variables.

If you want to get path use: path=$(echo $filename | sed -e ‘s/\/[^\/]*$/\//’) If you want to get extension: ext=$(echo $filename | sed -e ‘s/[^\.]*\.//’)

@Keith: for pathname, use path=$(dirname $filename) ; there isn’t a command to give you the extension per se, but @paxdiablo showed you how the shell can do it.

@Startec, because that’s how you run an executable (like basname ), capture it’s output, and use that output within a bash command as if you had typed it in explicitly. It’s similar to using backticks but with greater ease of nesting where necessary.

basename and dirname solutions are more convenient. Those are alternative commands:

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

This returns test.old.img like basename .

This is salt filename without extension:

And following statement gives the full path like dirname command.

It returns /opt/datastores/sda2

this doesn’t work if your path is just file.txt . your second code snipper should be sed -r «s/(.+\/)?(.+)\..+/\2/ instead

I’ve tested @Cardin. seems it works. FILE_PATH=»file.txt»; echo «$FILE_PATH» | sed «s/.*\///»; echo «$FILE_PATH» | sed -r «s/.+\/(.+)\..+/\1/»; echo «$FILE_PATH» | sed -r «s/(.+)\/.+/\1/»; returns 3 times file.txt

Here is an easy way to get the file name from a path:

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

To remove the extension you can use, assuming the file name has only ONE dot (the extension dot):

That’s not a good assumption, and there are tools and commands specificly designed to do this properly.

Additionally, I wouldn’t recommend using the variable name PATH , since this can conflict with the system’s PATH variable

This returns «bad substitution» in bash v4.4.7. I think Fırat KÜÇÜK’s sed solution is better, i.e. $(basename $the_file_path) | sed «s/\..*//»

Читайте также:  Настройка wine linux mint

For me this also gives «bad substitution» error in Bash 4.2.46. But it works if I replace order of operators, i.e. file=$(basename $)

Some more alternative options because regexes (regi ?) are awesome!

Here is a Simple regex to do the job:

Example (grep):

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

Example (awk):

 echo $FP | awk 'END #Or using stardard input awk 'END  

If you need a more complicated regex: For example your path is wrapped in a string.

 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" #usage grep -oP "$regex"  

Total solution with Regexes:

This function can give you the filename with or without extension of a linux filepath even if the filename has multiple "."s in it. It can also handle spaces in the filepath and if the file path is embedded or wrapped in a string.

#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="(? ## 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" 

If you have to mess with a windows path you can start with this one:

Источник

Как узнать имя файла скрипта в скрипте Bash?

Как определить имя файла Bash script внутри самого script? Как если бы мой script находился в файле runme.sh , то как бы я мог заставить его отображать сообщение "Вы используете runme.sh" без hardcoding, что?

Аналогично [Может ли bash-скрипт сказать, в каком каталоге он хранится?] ( To stackoverflow.com/questions/59895/… )

19 ответов

Для чтения через символическую ссылку, которая обычно не является тем, что вы хотите (вы обычно не хотите путать пользователя таким образом), попробуйте:

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")" 

IMO, что приведет к запутыванию вывода. "Я побежал foo.sh, но он сказал, что я бегу bar.sh!? Должно быть, ошибка!" Кроме того, одна из целей иметь разные имена символических ссылок заключается в предоставлении различных функциональных возможностей, основанных на имени, которое он назвал (думаю, gzip и gunzip на некоторых платформах).

Это работает, если вас не вызывают по символической ссылке. Но даже тогда, как правило, это то, что вы хотите в любом случае, IME.

Вы можете вызываться по имени, которое вообще не существует в виде файла - наиболее распространенный пример, вызов sh как «- / bin / sh» заставляет его действовать как оболочка входа в систему. Смотрите exec -a в Bash или execvp("/bin/foo", <"blah", . >) .

Если ваш сценарий меняет свое поведение в зависимости от того, как он вызывается, хорошая идея - обеспечить некоторую перехват всех при вычислении $ 0. В противном случае простая символическая ссылка может заставить его делать странные вещи 🙂 Т.е., если ссылка была названа foobar и только сценарий приходится на фу или бар.

-1, 1. readlink будет перемещаться только на одну символическую ссылку на глубину, 2. $0 в первом примере подвергается разбиению по словам, 3. $0 передается на basename, readlink и echo в позиции, которая позволяет рассматривать его как команду переключатель линии. Вместо этого я предлагаю me=$(basename -- "$0") или гораздо более эффективно за счет читабельности, me=$ . Для символических ссылок me=$(basename -- "$(readlink -f -- "$0")") предположении использования утилиты gnu, в противном случае это будет очень длинный скрипт, который я здесь не буду писать.

Не работает, если скрипт вызывается из другой папки. Путь включен во me . Протестировано с использованием GitBash.

Это достаточно хорошо, я часто использую его в своих сценариях, но есть способы вызывать сценарии, для которых это не будет работать (например, поиск), и я столкнулся с ними.

# ------------- SCRIPT ------------- # #!/bin/bash echo echo "# arguments called with ----> $ " echo "# \$1 ----------------------> $1 " echo "# \$2 ----------------------> $2 " echo "# path to me ---------------> $ " echo "# parent path --------------> $ " echo "# my name ------------------> $ " echo exit # ------------- CALLED ------------- # # Notice on the next line, the first argument is called within double, # and single quotes, since it contains two words $ /misc/shell_scripts/check_root/show_parms.sh "'hello there'" "'william'" # ------------- RESULTS ------------- # # arguments called with ---> 'hello there' 'william' # $1 ----------------------> 'hello there' # $2 ----------------------> 'william' # path to me --------------> /misc/shell_scripts/check_root/show_parms.sh # parent path -------------> /misc/shell_scripts/check_root # my name -----------------> show_parms.sh # ------------- END ------------- #

Не работает, если скрипт вызывается из другой папки. Путь включен в $ . Протестировано с использованием GitBash.

Вышеприведенное не работает для меня из скрипта .bash_login, но решение Dimitre Radoulov в $ BASH_SOURCE прекрасно работает.

С bash >= 3 работает следующее:

$ ./s 0 is: ./s BASH_SOURCE is: ./s $ . ./s 0 is: bash BASH_SOURCE is: ./s $ cat s #!/bin/bash printf '$0 is: %s\n$BASH_SOURCE is: %s\n' "$0" "$BASH_SOURCE" 

Это то, что я хочу, и легко использовать « dirname $BASE_SOURCE », чтобы получить каталог, в котором находятся сценарии.

Я почти усвоил эту разницу при написании сценария самоудаления. К счастью, «rm» получил псевдоним «rm -i» 🙂

в любом случае. ./s чтобы получить имя ./s вместо bash? Я обнаружил, что $ 1 не всегда установлен на ./s .

Если имя script содержит пробелы в нем, более надежным способом является использование "$0" или "$(basename "$0")" - или в MacOS: "$(basename \"$0\")" . Это препятствует тому, чтобы имя искажалось или интерпретировалось каким-либо образом. В общем, хорошей практикой всегда является двойное цитирование имен переменных в оболочке.

+1 за прямой ответ + лаконично. если вам нужны функции символической ссылки, я предлагаю посмотреть: ответ Трэвиса Б. Хартвелла.

$BASH_SOURCE дает правильный ответ при поиске script.

Это, однако, включает путь, чтобы получить только имя файла сценариев, используйте:

Этот ответ является ИМХО лучшим, потому что решение использует самодокументируемый код. $ BASH_SOURCE полностью понятен без чтения какой-либо документации, тогда как, например, $ <0 ## */>- нет

Если вы хотите его без пути, вы должны использовать $

Чтобы ответить Крис Конвей, на Linux (по крайней мере) вы сделаете следующее:

echo $(basename $(readlink -nf $0)) 

readlink выводит значение символической ссылки. Если это не символическая ссылка, она печатает имя файла. -n говорит, что не печатает новую строку. -f сообщает ему, чтобы он полностью следил за ссылкой (если символическая ссылка была ссылкой на другую ссылку, она также решила бы ее).

Эти ответы верны для случаев, о которых они заявляют, но проблема остается, если вы запускаете script из другого script с использованием ключевого слова 'source' (чтобы он работал в той же оболочке). В этом случае вы получаете $0 вызывающего script. И в этом случае я не думаю, что можно получить имя самого script.

Это краевой кейс и его нельзя воспринимать серьезно. Если вы запустите script из другого script напрямую (без "источника" ), использование $0 будет работать.

У вас есть очень хорошая мысль. Не крайний случай ИМО. Но есть решение: см . Ответ Дмитрия Радулова выше.

Я нашел, что эта строка всегда работает, независимо от того, был ли файл получен или запущен как script.

Если вы хотите следовать символическим ссылкам, используйте readlink по пути, который вы видите выше, рекурсивно или не рекурсивно.

Причина, по которой работает один лайнер, объясняется использованием переменной среды BASH_SOURCE и ее ассоциированной FUNCNAME .

BASH_SOURCE

Определяется переменная массива, членами которой являются исходные имена файлов, в которых определены соответствующие имена функций оболочки в переменной массива FUNCNAME. Функция оболочки $ определена в файле $ и вызывается из $.

имя_функции

Переменная массива, содержащая имена всех функций оболочки в настоящее время в стеке выполнения вызовов. Элемент с индексом 0 - это имя любой текущей исполняемой функции оболочки. Самый нижний элемент (тот, который имеет самый высокий индекс) является "основным". Эта переменная существует только при выполнении функции оболочки. Присвоения функции FUNCNAME не влияют и возвращают статус ошибки. Если функция FUNCNAME не установлена, она теряет свои специальные свойства, даже если она впоследствии reset.

Эта переменная может использоваться с BASH_LINENO и BASH_SOURCE. Каждый элемент FUNCNAME имеет соответствующие элементы в BASH_LINENO и BASH_SOURCE для описания стека вызовов. Например, $ вызывается из файла $ при номере строки $. С помощью этой информации встроенный caller отображает текущий стек вызовов.

Это работает , если вы источник в файле a (предположим , что «s содержание является a echo "$ - 1]>" ) с интерактивной сессии - то это даст вам a » ы путь , Но если вы напишите скрипт b с source a и запустите ./b , он вернет путь b .

Re: Tanktalus (принятый) ответ выше, немного более чистый способ использовать:

me=$(readlink --canonicalize --no-newline $0) 

Если ваш script был получен из другого bash script, вы можете использовать:

me=$(readlink --canonicalize --no-newline $BASH_SOURCE) 

Я согласен с тем, что было бы странно замечать символические ссылки, если ваша цель - предоставить обратную связь пользователю, но бывают случаи, когда вам нужно получить каноническое имя в script или другом файле, и это лучший способ, imo.

Источник

Оцените статью
Adblock
detector