Я хочу получить имя файла (без расширения) и расширение отдельно.
Лучшее решение, которое я нашел, это:
NAME=`echo "$FILE" | cut -d'.' -f1`
EXTENSION=`echo "$FILE" | cut -d'.' -f2`
Это неправильно, потому что не работает, если имя файла содержит несколько .
символов. Если, скажем, у меня есть a.b.js
, он будет рассматривать a
и b.js
, а не a.b
и js
.
Это может быть легко сделано в Python с
file, ext = os.path.splitext(path)
но я бы предпочел не запускать интерпретатор Python только для этого, если это возможно.
Есть идеи получше?
extension="{$filename##*.}"
как я это делал некоторое время! Переместите$
наружу кудряшки: Справа:extension="${filename##*.}"
os.path.splitext
Вместо этого я решил использовать Python, как указано выше ...Ответы:
Сначала получите имя файла без пути:
Кроме того, вы можете сосредоточиться на последнем «/» пути вместо «.» который должен работать, даже если у вас есть непредсказуемые расширения файлов:
Вы можете проверить документацию:
источник
basename
extension=$([[ "$filename" = *.* ]] && echo ".${filename##*.}" || echo '')
. Обратите внимание , что если расширение является присутствует, то он будет возвращен в том числе начального.
, например,.txt
.Для получения дополнительной информации см. Расширение параметров оболочки в руководстве по Bash.
источник
dinosaurs.in.tar
и вы ее разархивировалиdinosaurs.in.tar.gz
:)x.tar.gz
расширенияgz
и имя файла таковоx.tar
. Двойных расширений не существует. Я уверен, что Boost :: Filesystem справится с этим. (split path, change_extension ...) и его поведение основано на python, если я не ошибаюсь.Обычно вы уже знаете расширение, поэтому вы можете использовать:
например:
и мы получаем
источник
basename
довольно откровенен, ты добр, сэр / мадам :).zip
либо.ZIP
. Есть ли способ сделать что-то подобноеbasename $file {.zip,.ZIP}
?Вы можете использовать магию расширения параметров POSIX:
Есть предостережение в том, что если бы ваше имя файла имело форму,
./somefile.tar.gz
тоecho ${FILENAME%%.*}
жадно удаляло бы самое длинное совпадение с,.
и у вас была бы пустая строка.(Вы можете обойти это с помощью временной переменной:
)
Этот сайт объясняет больше.
источник
cut
нет--complement
иsed
не имеет-r
.Это не работает, если файл не имеет расширения или не имеет имени файла. Вот что я использую; он использует только встроенные функции и обрабатывает больше (но не все) патологических имен файлов.
И вот несколько тестов:
источник
dir="${fullpath:0:${#fullpath} - ${#filename}}"
я часто виделdir="${fullpath%$filename}"
. Проще написать. Не уверен, есть ли реальная разница в скорости или ошибки.which bash
->/bin/bash
; возможно это твой дистрибутив?Вы можете использовать
basename
.Пример:
Вам нужно предоставить базовое имя с расширением, которое должно быть удалено, однако, если вы всегда выполняете
tar
с этим,-z
вы знаете, что расширение будет.tar.gz
.Это должно делать то, что вы хотите:
источник
cd $(basename $1 .tar.gz)
работает для файлов .gz. Но в вопросе он упомянулArchive files have several extensions: tar.gz, tat.xz, tar.bz2
отлично работает, так что вы можете просто использовать:
Команды, кстати, работают следующим образом.
Команда для
NAME
замены"."
символа, за которым следует любое количество не"."
символов до конца строки, ничем (т. Е. Она удаляет все от"."
конца до конца строки включительно). Это в основном не жадная замена с использованием трюков с регулярными выражениями.Команда для
EXTENSION
замены любого числа символов, за которыми следует"."
символ в начале строки, ничем (т. Е. Она удаляет все от начала строки до конечной точки включительно). Это жадная замена, которая является действием по умолчанию.источник
sed 's,\.[^\.]*$,,'
для имени иsed 's,.*\.,., ;t ;g'
для расширения (использует нетипичныеtest
иget
команды, наряду с типичнойsubstitute
командой).Меллен пишет в комментарии к сообщению в блоге:
Используя Bash, можно также
${file%.*}
получить имя файла без расширения и${file##*.}
получить его отдельно. Это,Выходы:
источник
Нет необходимости беспокоиться
awk
илиsed
дажеperl
для этой простой задачи. Существует чисто Bash-os.path.splitext()
совместимое решение, которое использует только расширения параметров.Реализация ссылок
Документация
os.path.splitext(path)
:Код Python:
Реализация Bash
Чтение ведущих периодов
Игнорирование ведущих периодов
тесты
Вот тестовые примеры для реализации игнорирования ведущих периодов , которые должны соответствовать эталонной реализации Python на каждом входе.
Результаты теста
Все тесты пройдены.
источник
text.tar.gz
должно бытьtext
и расширение быть.tar.gz
os.path.splitext
в Python. Является ли эта реализация вменяемой для возможных противоречивых мнений - это еще одна тема."$root"
)? Что может произойти, если они были опущены? (Я не смог найти никакой документации по этому вопросу.) Кроме того, как это обрабатывает имена файлов с*
или?
в них?*
и?
не являются специальными. Таким образом, две части моего вопроса отвечают друг другу. Я прав, что это не задокументировано? Или это следует понимать из того факта, что кавычки отключают глобальное расширение вообще?root="${path#?}";root="${path::1}${root%.*}"
- затем выполните то же самое, чтобы извлечь расширение.Вы можете использовать
cut
команду для удаления двух последних расширений (".tar.gz"
часть):Как отметил Клейтон Хьюз в комментарии, это не будет работать для фактического примера в вопросе. Поэтому в качестве альтернативы я предлагаю использовать
sed
расширенные регулярные выражения, например:Он работает, удаляя последние два (буквенно-цифровые) расширения безоговорочно.
[Обновлено снова после комментария от Андерса Линдала]
источник
$
для проверки того, что соответствующее расширение находится в конце имени файла. В противном случае имя файлаi.like.tar.gz.files.tar.bz2
может привести к неожиданному результату.sed
порядку цепочек. Даже$
в конце имя файла, такое какmpc-1.0.1.tar.bz2.tar.gz
удалит оба,.tar.gz
а затем.tar.bz2
.Вот несколько альтернативных предложений (в основном, в
awk
), включая некоторые расширенные варианты использования, такие как извлечение номеров версий для пакетов программного обеспечения.Во всех случаях использования в качестве входных данных используется исходный полный путь, не зависящий от промежуточных результатов.
источник
Общепринятый ответ хорошо работает в типичных случаях , но не может в крайних случаях , а именно:
extension=${filename##*.}
возвращается имя входного файла, а не пустая строка.extension=${filename##*.}
не включает в себя начальные.
, вопреки соглашению..
не будет работать для имен файлов без суффикса.filename="${filename%.*}"
будет пустой строкой, если имя входного файла начинается с.
и не содержит дополнительных.
символов (например,.bash_profile
) - вопреки соглашению.---------
Таким образом, сложность надежного решения, охватывающего все граничные случаи, требует функции - см. Ее определение ниже; он может вернуть все компоненты пути .
Пример вызова:
Обратите внимание, что аргументы после входного пути выбираются свободно, имена позиционных переменных .
Чтобы пропустить не представляющие интереса переменные, которые предшествуют тем, которые есть, укажите
_
(для использования одноразовой переменной$_
) или''
; например, чтобы извлечь только имя файла и расширение, используйтеsplitPath '/etc/bash.bashrc' _ _ fnameroot extension
.Тестовый код, который выполняет функцию:
Ожидаемый результат - обратите внимание на крайние случаи:
.
( не считается началом суффикса)/
(трейлинг/
игнорируется).
возвращается как родительский путь).
токеном с префиксом (суффикс считается только последний):источник
Наименьшее и простое решение (в одну строку) это:
источник
echo
. В общем случае,echo $(command)
лучше писать просто,command
если только вы специально не требуете, чтобы оболочка выполнила токенизацию пробелов и расширение подстановочных знаков в выходных данныхcommand
перед отображением результата. Тест: каков результатecho $(echo '*')
(и если это то, что вы действительно хотите, вы действительно хотите простоecho *
).echo
команду. Я просто использовал его, чтобы продемонстрировать результат,foo
который появляется в 3-й строке как результат 2-й строки.basename "${file%.*}"
сделал бы то же самое; вы используете подстановку команд для захвата ее выходных данных, только дляecho
того же самого вывода немедленно. (Без кавычек результат номинально другой; но это вряд ли уместно, тем более, что особенность здесь.)basename "$file" .txt
избегает сложности подстановки параметров.Я думаю, что если вам просто нужно имя файла, вы можете попробовать это:
И это все = D.
источник
Вы можете принудительно вырезать для отображения всех полей и последующих, добавляя
-
к номеру поля.Так что, если ФАЙЛ
eth0.pcap.gz
, расширение будетpcap.gz
Используя ту же логику, вы также можете получить имя файла, используя '-' с cut следующим образом:
Это работает даже для имен файлов, которые не имеют никакого расширения.
источник
Волшебное распознавание файлов
В дополнение к множеству хороших ответов на этот вопрос переполнения стека я хотел бы добавить:
В Linux и других unixen существует волшебная команда с именем
file
, которая определяет тип файла, анализируя некоторые первые байты файла. Это очень старый инструмент, изначально используемый для серверов печати (если не создан для ... Я не уверен в этом).Расширения стандартов можно найти в
/etc/mime.types
(на моем Debian стола GNU / Linux См.man file
Иman mime.types
Возможно , вам придется установить.file
Полезность иmime-support
пакеты):Вы могли бы создать ударфункция для определения правильного расширения. Есть небольшой (не идеальный) образец:
Эта функция может установить переменную Bash, которую можно использовать позже:
(Это вдохновлено правильным ответом @Petesh):
источник
Итак, если я правильно понимаю, проблема здесь в том, как получить имя и полное расширение файла, который имеет несколько расширений, например
stuff.tar.gz
.Это работает для меня:
Это даст вам
stuff
как имя файла и.tar.gz
как расширение. Он работает для любого количества расширений, включая 0. Надеюсь, это поможет всем, у кого возникла такая же проблема =)источник
os.path.splitext
, чего хочет ОП)('stuff.tar', '.gz')
.Я использую следующий скрипт
источник
Это обслуживает несколько точек и пробелов в имени файла, однако, если нет расширения, оно возвращает само имя файла. Легко проверить, хотя; просто проверьте, что имя файла и расширение совпадают.
Естественно, этот метод не работает для файлов .tar.gz. Однако это может быть обработано в два этапа. Если расширение - gz, проверьте еще раз, есть ли расширение tar.
источник
Как извлечь имя файла и расширение в рыбе :
Предостережения: разделяет последнюю точку, что хорошо работает для имен файлов с точками в них, но не очень хорошо для расширений с точками в них. Смотрите пример ниже.
Применение:
Возможно, есть лучшие способы сделать это. Не стесняйтесь редактировать мой ответ, чтобы улучшить его.
Если вы имеете дело с ограниченным набором расширений и знаете их все, попробуйте это:
Это не имеет предостережения , как и в первом примере, но вы должны обрабатывать каждый случай , так что это может быть более утомительным , в зависимости от того , сколько расширений вы можете ожидать.
источник
Вот код с AWK . Это можно сделать проще. Но я не хорош в AWK.
источник
split()
.awk -F / '{ n=split($2, a, "."); print a[n] }' uses
/ `в качестве разделителя верхнего уровня, но затем разделяет вторые поля.
и печатает последний элемент из нового массива.Просто использовать
${parameter%word}
В твоем случае:
Если вы хотите проверить это, все последующие работы и просто удалите расширение:
источник
=
знаков не должно быть пробелов .Построение из ответа Петеша , если требуется только имя файла, путь и расширение могут быть разделены в одну строку,
источник
filename="$(basename "${fullname%.*}")"
basename
является необязательным, но указывает расширение для удаления. Подстановка все еще может быть полезной, но, возможно, наbasename
самом деле это не так, поскольку вы можете выполнять все эти подстановки с помощью встроенных команд оболочки.Основанный в основном на превосходном @ mklement0 и переполненном случайными, полезными башизмами, а также другими ответами на этот / другие вопросы / "этот чертов интернет" ... Я обернул все это в немного, немного более понятно, многоразовая функция мои (или ваш) ,
.bash_profile
который заботится о том , что (я считаю) должна быть более надежной версиейdirname
/basename
/ то , что у вас ..Примеры использования ...
источник
$IFS
(и если бы это было так, вы могли бы использовать егоlocal
для локализации). - Лучше использоватьlocal
переменные. - Ваше сообщение об ошибке должно быть выведеноstderr
, а неstdout
(использовать1>&2
), и вы должны вернуть ненулевой код выхода. - Лучше переименоватьfullname
вbasename
(первый предлагает путь с компонентами dir). -name
безоговорочно добавляет.
(точка), даже если оригинал не имеет ни одного. Вы можете просто использоватьbasename
утилиту, но обратите внимание, что она игнорирует завершение/
.Простой ответ:
Чтобы раскрыть ответ по переменным POSIX , обратите внимание, что вы можете создавать более интересные шаблоны. Таким образом, для случая, описанного здесь, вы можете просто сделать это:
Это прервет последнее появление .tar. <что - то> .
В целом, если вы хотите удалить последнее вхождение. <что - то> . <что-то еще> тогда
должно работать нормально.
Ссылка на ответ выше кажется мертвой. Вот отличное объяснение множества манипуляций со строками, которые вы можете выполнять непосредственно в Bash из TLDP .
источник
Если вы также хотите разрешить пустые расширения, это самое короткое, что я могу придумать:
1-я строка объяснила: он соответствует PATH.EXT или НИЧЕГО и заменяет его на EXT. Если НИЧЕГО было найдено, группа ext не перехватывается.
источник
Это единственный, который работал на меня:
Это также может быть использовано в интерполяции строк, но, к сожалению, вы должны установить
base
заранее.источник
Вот алгоритм, который я использовал для нахождения имени и расширения файла, когда писал сценарий Bash, чтобы сделать имена уникальными, когда имена конфликтуют по отношению к регистру.
Тестовый прогон.
К вашему сведению: полную программу транслитерации и другие тестовые примеры можно найти здесь: https://www.dropbox.com/s/4c6m0f2e28a1vxf/avoid-clashes-code.zip?dl=0
источник
extension=$([[ "$theFileName" == *.* ]] && echo ".${theFileName##*.}" || echo '')
Используя пример файла
/Users/Jonathan/Scripts/bash/MyScript.sh
, этот код:приведет к
${ME}
тому, чтобы бытьMyScript
и${MY_EXT}
быть.sh
:Автор сценария:
Некоторые тесты:
источник
basename
, возможно, излишне.Из ответов выше, самый короткий oneliner для имитации Python
Предполагая, что ваш файл действительно имеет расширение,
источник
EXT
так что это черепахи до конца. (Кроме того, вам следует избегать использования заглавных букв в именах ваших личных переменных; они зарезервированы для системных переменных.)