Bash имя файла без расширения
на имени команда имеет два разных вызова; в одном вы указываете только путь, в этом случае он дает вам последний компонент, а в другом вы также даете суффикс, который он удалит. Таким образом, вы можете упростить свой пример кода, используя второй вызов basename. Кроме того, будьте осторожны, чтобы правильно цитировать вещи:
комбинация basename и cut отлично работает, даже в случае двойного окончания, такого как .tar.gz :
было бы интересно, если это решение требует меньше арифметической мощности, чем расширение параметра Bash.
чисто bash , нет basename , нет переменной жонглирование. Установите строку и echo :
Примечание: bash extglob опция должна быть "on", (on Ubuntu это" on " по умолчанию), если это не так, сделайте:
- $$s.
- // замените каждый экземпляр узор.
- +( матч один или несколько на список шаблон в скобках.
- *\/ все матчи до / . (1-й образец)
- | или. (разделитель шаблонов.)
- .* соответствует что-нибудь после . . (2-й образец)
- ) конец список шаблон.
- > параметр расширения, поскольку нет / (который предшествует замене строки), совпадающие шаблоны удаляются.
соответствующей man bash справочная информация:
мне это было нужно, так же, как спросили bongbang и w4etwetewtwet.
вот еще один (более сложный) способ получить имя файла или расширение, сначала используйте rev команда инвертировать путь к файлу, вырезать из первого . а затем снова инвертируйте путь к файлу, например:
Если вы хотите играть хорошо с путями файлов Windows (под Cygwin), вы также можете попробовать следующее:
это будет учитывать разделители обратной косой черты при использовании BaSH в Windows.
Примечание: пожалуйста, посоветуйте мне использовать цитаты; это сработало для меня, но я мог бы пропустить что-то по их правильному использованию (я, вероятно, использую слишком много).
нужен способ выделить расширение из имени файла. в гугле нашел такой способ:
по проблема в том, что выделяется только последняя часть, после последней точки. т.е. из «file.tar.gz» выделяется «gz»
подскажите, как правильно сделать?
>по проблема в том, что выделяется только последняя часть, после последней точки. т.е. из «file.tar.gz» выделяется «gz»
В чём проблема? Это и есть расширение.
проблема в том, что хочется чтоб из «file.txt» выделялось «txt», а из «file.tar.gz» выделялось «tar.gz» :)
Более корректно будет так:
echo facepalm.jpg |grep -Eo '\.[^.]+$'
echo «$filename» | sed 's/^[a-zA-Z0-9а-яА-Я]*\.//'
echo facepalm.jpg.lzma |grep -Eo '\..+$'
а из всех приведенных способов, какой будет самый корректный? оО
если для этого варианта передать имя файла в котором еще и версия присутствует, то и она выделяется.
к примеру из «file-1.14.tar.gz» получим ".14.tar.gz"
тут наверное одним вариантом не обойтись. нужно проверять кол-во точек, и если их две и более - извлекать только две, иначе одну.
Во-первых, нет такого слова «расширение». Часть имени после точки называется суффиксом. И суффиксов может быть несколько. Если нужен только последний, то sed'ом проще всего выделить:
И что будет в случае «file-1.14.tar»?
А если file.with.dots.but.without.extension? Или I.like.dots.txt?
Это только для DOS'образных ОСей.
A filename extension is a suffix (separated from the basefilename by a dot) to the name of a computer file applied to indicate the encoding (file format) of its contents or usage.
Общее определение термина, OS-agnostic. DOS не упоминается.
Some filesystems limit the length of the extension (such as the FAT file system not allowing more than three characters) while others (such as NTFS) do not. Unix filesystems accept the separator dot as a legal character.
Замечание, в котором упоминаются файловые системы Unix-like осей.
Просто признай, что у тебя ДИРЕКТОРИЯ головного мозга.
тащемта правильно определять MIME тип, а потом уже откусывать по нему екстеншн.
не читайте на ночь википедиков
ну проверяйте. тут одним регекспом не обойтись, вам скрипт на sed написать? ИМХО практической пользы в нём нет.
и да, откройте же для себя команду file
А также в интернеты не ходить и гугл не использовать? Ну-ну.
> проблема в том, что хочется чтоб из «file.txt» выделялось «txt», а из «file.tar.gz» выделялось «tar.gz» :)
А из файла filename.program.text.2011.11.24.log.tar.gz ?
>А также в интернеты не ходить и гугл не использовать? Ну-ну.
что ну-ну? Есть постфиксная часть имени, проще говоря в конце файла. Но она вовсе необязательно начинается с точки и точек не содержит. И совсем не обязательно говорит о типе файлов. Посмотрите на многотомные архивы например. Это только в венде так.
> И совсем не обязательно говорит о типе файлов.
То, что суффикс не говорит о типе файла, всего лишь означает, что он не является расширением.
Если суффикса нет, то и расширения нет, что тоже вполне нормально, так как нигде не сказано в определении, что имя файла обязано его иметь.
Там сказано всего лишь, что суффикс (отделенный точкой), который говорит о типе файла, называется «расширением имени файла».
Возможно, с примером тебе будет проще понять о чем речь.
Я возьму файл из моей генты - «gzip.py», который валяется в где-то /usr/lib/python2.7:
1. У этого файла есть суффикс, отделенный точкой? Имеется, «py».
2. Этот суффикс говорит о типе файла? Говорит.
Откуда следуют, что он по определению является расширением имени файла.
И после этого ты будешь утверждать, что они бывают только венде?
Возможно, конечно, что ты не согласен с таким определением, но в таком случае будь добр, приведи ссылку на корректное.
>1. У этого файла есть суффикс, отделенный точкой? Имеется, «py». >2. Этот суффикс говорит о типе файла? Говорит.
1. имеется.
2. не говорит. А лишь намекает.
Откуда следуют, что он по определению является расширением имени файла.
по ТВОЕМУ определению.
И после этого ты будешь утверждать, что они бывают только венде?
Да, конечно. По той простой причине, что та сущность, которую обычно воспринимают как «расширения» в венде, в линуксе отсутствует напрочь. Как известно, маздайщики обделены нормальной консолью, и нормальными ФМ, у них на всё про всё explorer.exe. А эта программа считает «расширением» последние символы имени после последней точки. И в соответствие с данным расширением отправляет файл при открытие в жёстко выбранное приложение. Вот _такой_ сущности в линуксе не было, нет, и я надеюсь уже не будет.
Возможно, конечно, что ты не согласен с таким определением, но в таком случае будь добр, приведи ссылку на корректное.
Я вообще считаю, что узнавать тип файла по его имени - ненадёжно, и вообще Must Die. Можно воспользоваться например расширенными атрибутами. ИМХО, «Месячный отчёт за январь» куда как аккуратней и осмысленней, чем «Месячный отчёт за январь.ODT». Скрывать расширения - жуткий маздайный костыль, но тип определять таки надо. И у нас есть для этого механизм - xattr, там можно хранить тип файлов, что-бы знать, какой программой это всё надо открывать.
> 2. не говорит. А лишь намекает.
В венде тоже «лишь намекает». Никто не мешает мне поменять .doc на .py в отдельном имени файла. Это везде так, линупс тут особенным не является. Так что таки «говорит», насколько оно может говорить.
Не по моему, а по определению из Вики. Ты же так и не привел «СВОЕГО».
По той простой причине, что та сущность, которую обычно воспринимают как «расширения» в венде, в линуксе отсутствует напрочь.
Мой пример показывает обратное, но ты закрыл на него глаза. Хотя это зависит от определения, лично я воспринимаю так, как написано в Вике, думаю, что и большинство других людей так же воспринимают. У тебя, похоже, какое-то свое особое восприятие.
Вот _такой_ сущности в линуксе не было, нет, и я надеюсь уже не будет.
Я вообще считаю, что узнавать тип файла по его имени - ненадёжно, и вообще Must Die.
Не относится к теме дискуссии. Речь не про то, как часто расширения используются или не используются программами, и даже не про надежность этих суффиксов.
Есть термин, который описывает конкретную вещь, и независимо от твоего восприятия, в линупсах есть сущности, которые попадают под это описание.
Кстати, некоторые утилиты по умолчанию отказываются работать с файлами с неправильным расширением, gzip в качестве примера:
gzip: file.hz: unknown suffix — ignored
Пока ты не приведешь «корректного» определения, спорить дальше смысла не имеет. Разумеется я ожидаю ссылку на «надежный» источник.
>Не по моему, а по определению из Вики. Ты же так и не привел «СВОЕГО».
вике я не доверяю, и особенно по части определений. А своё «определение» я уже привёл: нет никаких расширений. Не, конечно если у фалов есть что-то общее, то можно им дать какие-нить особые имена, и парсить имена легче, если «особость» в конце. Но вот чем там разделять, и что там брать - каждый решает сам. Или сами, если группа людей делает одно дело. Что мы и наблюдаем. По этой причине создать универсальный регексп невозможно, он будет постоянно фэйлится. Можно создать только регексп для известной группы файлов, да и то, нет гарантии, что он не сломается.
Мой пример показывает обратное, но ты закрыл на него глаза.
потому-что это всего-лишь один, частный, и не очень таки распространённый вариант.
хотя это зависит от определения, лично я воспринимаю так, как написано в Вике, думаю, что и большинство других людей так же воспринимают. У тебя, похоже, какое-то свое особое восприятие.
в том-то и дело, что люди, знакомые с понятиями «папка», «расширение» переносят эти простые и понятные слова и в Linux. ВНЕЗАПНО выясняется, что исключений у этих терминов больше чем правил - расширения например часто дают разные, или не дают их вовсе. И всем - пофиг. Захотел один - назвал архив a.txz, а другой a.tar.xz, а третий так вообще tar+xza. У людей жесточайщий баттхёрт - как-же, да этого быть не может! Но это так.
Есть термин, который описывает конкретную вещь, и независимо от твоего восприятия, в линупсах есть сущности, которые попадают под это описание.
утверждение: «Все бабы бл*и». IRL полно сущностей, которые попадают под это правило. Ну и что?
Кстати, некоторые утилиты по умолчанию отказываются работать с файлами с неправильным расширением, gzip в качестве примера:
gzip: file.hz: unknown suffix — ignored
Пока ты не приведешь «корректного» определения, спорить дальше смысла не имеет. Разумеется я ожидаю ссылку на «надежный» источник.
именно это я и объяснял ТС'у - нет никакого валидного определения расширений, а следовательно мы их никак не сможем фильтровать. Хотя в частных случаях, как с gzip'ом - очень даже и можем. Но это относится _только_ к gzip'у.
И да, в Slackware Linux less умеет читать *.gz файлы, самостоятельно их распаковывая. Казалось-бы, отличный пример! АВХ! В CentOS less такого не умеет, и нужно использовать спецверсию zless. Как видишь, все эти расширения иллюзорны и ненадёжны. Они надёжны лишь покуда ты их сам рисуешь.
Без шуток, на полном серьёзе. У меня и таких, и таких файлов найдётся немало.
Поучаствую и я в срачике.
По той простой причине, что та сущность, которую обычно воспринимают как «расширения» в венде, в линуксе отсутствует напрочь.
Расскажи это, например, gcc, ок? По-твоему, мне каждый раз при компиляции/других действиях с исходным кодом надо указывать, какого же типа исходный код? Нет, спасибо, я лучше один раз файл назову.
Я вообще считаю, что узнавать тип файла по его имени - ненадёжно, и вообще Must Die.
Хорошо, как ты предлагаешь определять тип файла?
Как file, по сигнатурам? Это не оптимально, сигнатур может быть много, проверять каждую - куча времени уйдёт; а если у меня _много_ файлов, и мне для каждого тип надо определить?
Хранить расширенный атрибут? Чем это лучше расширений?
Тем, что расширение ненадёжно, легко можно изменить? С расширенными атрибутами так же.
Тем, что якобы название без расширения более осмысленно? Не гони пургу, я - не компьютер, не могу одним взглядом на файл прочитать заодно расширенные атрибуты. А вот если в названии есть расширение, то мне сразу ясно, где тут odt, где тут txt, а где картинки.
Более того, ты не рассматриваешь ситуацию, когда в одном месте лежат файлы с одинаковыми названиями, но разными расширениями. Что в этом случае делать будешь?
Ну и последнее, давай не будем забывать, что винда есть, нравится это тебе или нет, и обмениваться с ней файлами тоже необходимо. А она ничего не знает про расширенные атрибуты, что с ней прикажешь делать?
> вике я не доверяю, и особенно по части определений.
А я тебе не доверяю.
А своё «определение» я уже привёл
Я просил привести ссылку на надежный источник, ты таковым не являешься.
Но термин-то есть, и люди, включая тебя, вкладывают в него какой-то смысл. «Нет никаких расширений» не является значением термина «расширение имени файла».
потому-что это всего-лишь один, частный, и не очень таки распространённый вариант.
С логикой проблемы? Для того, чтобы доказать существование чего-то, достаточно привести всего один пример (хотя я мог бы показать куда больше).
утверждение: «Все бабы бл*и». IRL полно сущностей, которые попадают под это правило. Ну и что?
О боги! Ну почитай ты уже какой-нибудь учебник по логике, это первый курс любой вменяемой специальности.
Я доказывал утверждение «Существует x из X, такое что выполняется P», а не «Для любого x из X выполняется P».
Чтобы _доказать_ существование, нужно привести пример, где P выполняется (всего один!).
Утверждение в твоей убогой аналогии попадает под второй случай, и одним примером, где выполняется !P (т.е найти «не шлюху»), его можно _опровергнуть_.
именно это я и объяснял ТС'у - нет никакого валидного определения расширений, а следовательно мы их никак не сможем фильтровать.
Определение (в смысле «значение») есть (и судя по всему, ты им даже пользуешься, хоть и пытаешься это отрицать), нет способа определить.
Но то, что нет никакого валидного способа определить расширение файла, не означает, что их не существует. Более того, это вообще не имеет значения.
Еще раз повторяю, я доказывал (и доказал) «расширения существуют», а не «у каждого имени файла имеется расширение, и существует достоверный способ его определить».
Хотя в частных случаях, как с gzip'ом - очень даже и можем. Но это относится _только_ к gzip'у.
Чтобы доказать «не существование» расширений, тебе нужно было показать, что во всех возможных случаях у имени файла нет расширения, вместо того чтобы приводить некорректные аналогии, плакаться о вендопроблемах и рассказывать про то, что нет способов валидного определения.
Но ты уже согласился, что частные случаи существуют, чем и подтвердил утверждение о существовании ;)
И на этом мне пора закончить комментировать твое неосиляторство логики.
>Расскажи это, например, gcc, ок? По-твоему, мне каждый раз при компиляции/других действиях с исходным кодом надо указывать, какого же типа исходный код? Нет, спасибо, я лучше один раз файл назову.
зачем-же так грубо? Ну во первых, мы всегда можем написать gcc | g++ | g77 | etc, во вторых, я не призываю вот прямо сейчас взять, и закопать. Просто надо сменить своё отношение к суффиксам. Ну а в третьих, на выходе из gcc мы обычно получаем исполняемый файл, без всяких расширений, и тем не менее отлично работающий.
Как file, по сигнатурам? Это не оптимально, сигнатур может быть много, проверять каждую - куча времени уйдёт; а если у меня _много_ файлов, и мне для каждого тип надо определить?
почему-же не оптимально? подождёшь 0.1 секунды на определения фильма, который ты полчаса качал. Но я не предлагаю это делать каждый раз - тип файла должен в идеале передаваться вместе с файлам, как уже запиливают в Kademlia. Ну а на старых каналах - архивы и file. Как временные костыли.
Хранить расширенный атрибут? Чем это лучше расширений?
давай будем хранить инициалы автора в поле mtime? А чё, там 64 бита, всё равно никто не юзает с наносекундной точностью. Миллисекунд хватит всем!
Пойми, эти «расширения» - костыль со времён MS-DOS, если не раньше. Тогда да, надо было. Но не сейчас-же! Наши HDD не в силах сохранить пару десяток байт на файл? ФС не позволяет? Или что?
Имя - единая и не делимая сущность, мало того, она не имеет прямого отношения к содержимому файлов. Это просто ссылка, коих может быть сколько угодно, и не быть вовсе. Зачем туда пихать информацию о типе содержимого?! Это в досе было оправданно имя--содержимое. А у нас имена без сродержимого на диске (fifo), и файлы на диске со многими именами. Нету у нас такой связи уже. Уже лет так 30+.
Тем, что якобы название без расширения более осмысленно? Не гони пургу, я - не компьютер, не могу одним взглядом на файл прочитать заодно расширенные атрибуты. А вот если в названии есть расширение, то мне сразу ясно, где тут odt, где тут txt, а где картинки.
Более того, ты не рассматриваешь ситуацию, когда в одном месте лежат файлы с одинаковыми названиями, но разными расширениями. Что в этом случае делать будешь?
в этой ситуации - оставлю как есть. Я что, запрещаю зать эти ваши расширения? Я что, Поттеринг? Не хочешь - не юзай. Сам же мне спасибо скажешь, когда твоя ls/mc/ФМ научится отличать скрипт от ELF'а.
Ну и последнее, давай не будем забывать, что винда есть, нравится это тебе или нет, и обмениваться с ней файлами тоже необходимо. А она ничего не знает про расширенные атрибуты, что с ней прикажешь делать?
This code should work in most cases as long as the value of $1 is actually what you think it is. However, it is subject to word splitting and filename expansion due to improper quoting.
Closer @tripleee: this is not a duplicate of Extract filename and extension in Bash. The other more complex Q requires the extension and filename be separate. If anything, the other Q. is an elaboration of this more basic one.
@agc The answers seem very similar, but the older question has more of them. Can you explain why you think these should be kept separate?
@tripleee Users interested in the simpler problem might be needlessly confused by the added or differing code required to solve the more complex problem.
Did you read the answers to the other question? Out of the top five, four very distinctly demonstrate how to do exactly this, and explain the options, most of them quite succinctly. I'm happy to be convinced if you can point to actual differences, but I'm not seeing them. Perhaps raise this on Meta Stack Overflow for broader visibility.
15 Answers 15
You can also use parameter expansion:
Just be aware that if there is no file extension, it will look further back for dots, e.g.
- If the filename only starts with a dot (e.g. .bashrc ) it will remove the whole filename.
- If there's a dot only in the path (e.g. path.to/myfile or ./myfile ), then it will trim inside the path.
And here I was about to use echo -n "This.File.Has.Periods.In.It.txt" | awk -F. '' | tr ' ' '.' | rev | cut -c 2- | rev . Thanks.$NF="";>
Be warned this deletes the entire name if there is no extension and the path is relative. E.g., filename=./ihavenoextension .
You should be using the command substitution syntax $(command) when you want to execute a command in script/command.
So your line would be
- echo get the value of the variable $filename and send it to standard output
- We then grab the output and pipe it to the cut command
- The cut will use the . as delimiter (also known as separator) for cutting the string into segments and by -f we select which segment we want to have in output
- Then the $() command substitution will get the output and return its value
- The returned value will be assigned to the variable named name
Note that this gives the portion of the variable up to the first period . :
The problem with this answer is it assumes input string has ONLY one dot . @chepner below has a much better solution . name=$
This answer is characteristic of beginners and should not be spreaded. Use the builtin mechanism as described by chepner's answer
If you know the extension, you can use basename
@GabrielStaples you could combine it with dirname , e.g. file=/home/jsmith/base.wiki; echo $(dirname $file)/$(basename $file .wiki)
I went with this. The nice thing is that basename is made for this and I discovered a new capability in what it can do.
If your filename contains a dot (other than the one of the extension) then use this:
It’s even better with an -s option given to cut , so that it returns an empty string whenever the filename contains no dot.
This should be the accepted answer in my opinion, since it works on path with dots in them, with hidden files starting with a dot, or even with file with multiple extensions.
@FedonKadifeli, this works for just the file name, not for full path. But you can get the filename first using a similar approach by using / as the delimiter.
use whichever you want. Here I assume that last . (dot) followed by text is extension.
What happens when file1=/tmp.d/mainonetwosh ? The sed expression should be replaced with 's/\.[^./]*$//'
Using POSIX's built-in only:
Note that only the last extension is removed.
My recommendation is to use basename .
It is by default in Ubuntu, visually simple code and deal with majority of cases.
Here are some sub-cases to deal with spaces and multi-dot/sub-extension:
It usually get rid of extension from first . , but fail in our .. path
Here is an important note:
I used double quotes inside double quotes to deal with spaces. Single quote will not pass due to texting the $. Bash is unusual and reads "second "first" quotes" due to expansion.
However, you still need to think of .hidden_files
not the expected "" outcome. To make it happen use $HOME or /home/user_path/
because again bash is "unusual" and don't expand "~" (search for bash BashPitfalls)
Answers provided previously have problems with paths containing dots. Some examples:
I prefer to use |sed -e 's/\.[^./]*$//' . For example:
Note: If you want to remove multiple extensions (as in the last example), use |sed -e 's/\.[^/]*$//' :
However, this method will fail in "dot-files" with no extension:
To cover also such cases, you can use:
@gniourf_gniourf upvoting because you've made it a useful answer by showing how to correctly use it with a variable.
As pointed out by Hawker65 in the comment of chepner answer, the most voted solution does neither take care of multiple extensions (such as filename.tar.gz), nor of dots in the rest of the path (such as this.path/with.dots/in.path.name). A possible solution is:
This one strips "tar.gz" by selecting characters before the first instance of a dot in the filename not counting the path. One probably doesn't want to strip extensions that way.
If you know it ends in .tar.gz , you can just use $(basename "$a" .tar.gz) . Also, make sure to wrap your variable in quotes everywhere if there's any chance it will contain spaces or other weird characters!
This one covers all possibilities! (dot in the path or not; with extension or no extension):
tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $);echo $filename_noextension
- It gives you the filename without any extension. So there is no path in the $filename_noextension variable.
- You end up with two unwanted variables $tmp1 and $tmp2 . Make sure you are not using them in your script.
examples to test:
filename=.bashrc; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
filename=.bashrc.txt; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
filename=.bashrc.txt.tar; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
filename=~/.bashrc; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
filename=~/.bashrc.txt.tar; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
filename=bashrc; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
filename=bashrc.txt; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
filename=bashrc.txt.tar; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
filename=~/bashrc; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
filename=~/bashrc.txt.tar; echo "filename: $filename"; tmp1=$;tmp2=$;filename_noextension=$(echo -n $;echo $); echo "filename without extension: $filename_noextension"
Я хочу, чтобы получить имя файла (без расширения) и расширение отдельно.
лучшее решение я нашел до сих пор:
это неправильно, потому что он не работает, если имя файла содержит несколько . символы. Если, скажем, у меня есть a.b.js , он будет рассматривать a и b.js , вместо a.b и js .
это можно легко сделать в Python с
но я бы предпочел не запускать Python переводчик только для этого, если возможно.
во-первых, получить имя файла без пути:
кроме того, вы можете сосредоточиться на последнем " / "пути вместо". который должен работать даже если у вас есть непредсказуемо расширениями:
дополнительные сведения см. В разделе расширение параметров оболочки в руководстве Bash.
обычно вы уже знаете расширение, поэтому вы можете использовать:
вы можете использовать магию переменных POSIX:
в этом есть оговорка, если ваше имя файла было в форме ./somefile.tar.gz затем echo $ жадно удалил бы самую длинную спичку в . и у вас будет пустая строка.
(вы можете обойти это с помощью временной переменной:
этой сайт больше объясняет.
это не работает, если файл не имеет расширения или имени файла. Вот что я использую; он использует только встроенные имена и обрабатывает больше (но не все) патологические имена файлов.
и вот некоторые тестовые примеры:
вам нужно предоставить basename с расширением, которое должно быть удалено, однако, если вы всегда выполняете tar С -z тогда вы знаете, что расширение будет .tar.gz .
это должно делать то, что вы хотите:
отлично работает, поэтому вы можете просто использовать:
команды, кстати, работают следующим образом.
команда NAME заменяет a "." символ, за которым следует любое число "." символы до конца строки, без ничего (т. е. он удаляет все из final "." до конца строки включительно). Это в основном не жадная подстановка с использованием обмана regex.
команда EXTENSION заменители a любое количество символов, за которыми следует "." символ в начале строки, без ничего (т. е. он удаляет все от начала строки до конечной точки, включительно). Это жадная подстановка, которая является действием по умолчанию.
используя Bash, есть также $ получить имя файла без расширения и $ чтобы получить расширение в одиночку. То есть,
можно использовать cut команда для удаления последних двух расширений ( ".tar.gz" часть):
как отметил Клейтон Хьюз в комментарии, это не будет работать на конкретном примере в вопросе. Поэтому в качестве альтернативы я предлагаю использовать sed с расширенными регулярными выражениями, например:
он работает, удаляя последние два (альфа-числовые) расширения безоговорочно.
[Обновлено снова после комментария от Андерса Линдаля]
нет необходимости беспокоиться с awk или sed или даже perl для этой простой задачи. Есть чистый-Баш, os.path.splitext() -совместимое решение, которое использует только разложений параметра.
разделить путь пути на пару (root, ext) такое, что root + ext == path и ext пусто или начинается с точки и содержит не более одного периода. Ведущие периоды базовое имя игнорируется; splitext('.cshrc') возвращает ('.cshrc', '') .
почитание ведущих периодов
игнорирование ведущих периодов
вот тестовые примеры для игнорирование ведущих периодов реализация, которая должна соответствовать ссылочной реализации Python на каждом входе.
вот некоторые альтернативные предложения (в основном в awk ), включая некоторые расширенные варианты использования, такие как извлечение номеров версий для пакетов программного обеспечения.
все варианты использования, используя исходный полный путь в качестве входных данных, вне зависимости от промежуточных результатов.
[Пересмотрено с однострочного до общего bash функции поведение сейчас соответствует dirname и basename служебные программы; обоснование добавил.]
на принято отвечать работает в типичный делам, а не в edge делам, а именно:
- для имен файлов без расширения (называется суффикс в остальной части этот ответ), extension=$ возвращает входное имя файла, а не пустая строка.
- extension=$ не включает начальное . , противоречит Конвенции.
- слепо знаком . не будет работать для имен без суффикса.
таким образом, сложность робастное разрешение которое покрывает все случаи края требует функции - см. его определение ниже; это может возвратить все компоненты контура.
обратите внимание, что аргументы после входного пути свободно выбираются, позиционная переменная имена.
Пропустить переменные не из проценты, которые приходят перед теми, которые есть, укажите _ (использовать выбрасываемую переменную $_ ) или '' ; например, чтобы извлечь только корень и расширение файла, используйте splitPath '/etc/bash.bashrc' _ _ fnameroot extension .9 Answers 9
You don't have to call the external basename command. Instead, you could use the following commands:
Note that this solution should work in all recent (post 2004) POSIX compliant shells, (e.g. bash , dash , ksh , etc.).
The basename command has two different invocations; in one, you specify just the path, in which case it gives you the last component, while in the other you also give a suffix that it will remove. So, you can simplify your example code by using the second invocation of basename. Also, be careful to correctly quote things:
@handuel Unfortunately, basename does not support wildcards. Providing a second argument will only remove that exact literal string from the end.
On machines with basename 8.4, it works just as just as specified in this answer, but for me (with basename 8.22 from GNU coreutils) this worked as basename -s
. A combination of basename and cut works fine, even in case of double ending like .tar.gz :
Would be interesting if this solution needs less arithmetic power than Bash Parameter Expansion.
This is my preferred way - with the minor change of using $(..) - so this becomes: fbname=$(basename "$fullfile" | cut -d. -f1)
If a file has dots elsewhere in the name, this would truncate it incorrectly. This may work better: fbname=$(basename "$fullfile" | sed -r 's|^(.*?)\.\w+$|\1|') . More choices: : 's|^(.*?)\..+$|\1|' , 's|^(.*?)\.[^\.]+$|\1|' .
Here are oneliners:
I needed this, the same as asked by bongbang and w4etwetewtwet.
Pure bash , no basename , no variable juggling. Set a string and echo :
Note: the bash extglob option must be "on", (Ubuntu sets extglob "on" by default), if it's not, do:
in a shell gives me the output I want, test . I already know $filename has been assigned the right value. What I want to do is assign to a variable the filename without the extension.
basename $filename .exe would do the same thing. That's assuming you always know what extension you want to remove.
Читайте также: