Я закончил тем, что использовал это, потому что это было самым гибким, и было несколько других подобных вещей, которые я хотел сделать, и это сделало хорошо.
Лоуренс Джонстон
Это, пожалуй, самый гибкий из всех опубликованных ответов, но я думаю, что ответы, предлагающие команды basename и dirname, также заслуживают некоторого внимания. Они могут быть просто уловкой, если вам не нужно какое-либо другое причудливое сопоставление с образцом.
mgadda
7
Что это называется $ {x% .bar}? Я хотел бы узнать больше об этом.
Василий
14
@Basil: расширение параметров. В консоли введите «man bash», а затем введите «/ extension extension»
Zan Lynx
1
Я думаю, что объяснение «man bash» имеет смысл, если вы уже знаете, что он делает, или если вы сами попробовали его. Это почти так же плохо, как Git Reference. Я бы просто погуглил.
Вероятно, самое простое из всех предлагаемых в настоящее время решений ... хотя я бы использовал $ (...) вместо обратных кавычек.
Майкл Джонсон
6
Проще всего, но добавляет зависимость (не огромную или странную, я признаю). Также необходимо знать суффикс.
Винко Врсалович
И может использоваться для удаления чего-либо с конца, в основном это просто удаление строки с конца.
Смар
2
Проблема во времени. Я только что искал вопрос для этого обсуждения после просмотра bash почти 5 минут, чтобы обработать 800 файлов, используя базовое имя. Используя вышеупомянутый метод регулярных выражений, время было сокращено примерно до 7 секунд. Хотя этот ответ проще для программиста, время просто слишком велико. Представьте себе папку с парой тысяч файлов в ней! У меня есть несколько таких папок.
xizdaqrian
@xizdaqrian Это абсолютно неверно. Это простая программа, которая не должна возвращаться за полсекунды. Я только что выполнил поиск времени / home / me / dev -name "* .py" .py -exec basename {} \; и это лишило расширение и каталог для 1500 файлов за 1 секунду всего.
Ласло Трешкай
40
Чистый bash, сделанный в двух отдельных операциях:
Удалить путь из строки пути:
path=/foo/bar/bim/baz/file.gif
file=${path##*/} #$file is now 'file.gif'
Используя basename, я использовал следующее для достижения этой цели:
for file in*;do
ext=${file##*.}
fname=`basename $file $ext`# Do things with $fnamedone;
Это не требует априорных знаний о расширении файла и работает, даже если у вас есть имя файла с точками в имени файла (перед его расширением); basenameХотя для этого требуется программа , но это часть ядра GNU Coreutils, поэтому она должна поставляться с любым дистрибутивом.
Эта функциональность описана на man bash в разделе «Расширение параметров». Существует множество способов, не связанных с bash: awk, perl, sed и так далее.
РЕДАКТИРОВАТЬ: работает с точками в суффиксах файлов и не нужно знать суффикс (расширение), но не работает с точками в самом имени .
Было бы полезно исправить здесь кавычки - возможно, запустите это через shellcheck.netmystring=$1 вместо текущего постоянного значения (которое будет подавлять несколько предупреждений, будучи уверенным, что они не содержат пробелы / символы глобуса / и т. Д.), И решите проблемы, с которыми оно связано находки?
Чарльз Даффи
Что ж, я сделал некоторые соответствующие изменения для поддержки кавычек в $ mystring. Черт возьми, это было давным-давно, я написал это :)
Иерув
Было бы дальнейшее улучшение, чтобы процитировать результаты: echo "basename: $(basename "$mystring")"- таким образом, если mystring='/foo/*'вы не получите *замену со списком файлов в текущем каталоге послеbasename завершения.
Чарльз Даффи
6
Использование basenameпредполагает, что вы знаете, что такое расширение файла, не так ли?
И я считаю, что различные предложения по регулярным выражениям не справляются с именем файла, содержащим более одного "."
Следующее, кажется, справляется с двойными точками. Да, и имена файлов, которые содержат "/" сами (только для ударов)
Перефразируя Паскаля: «Извините, этот скрипт такой длинный. У меня не было времени сделать его короче»
Это даже можно сделать безопасным для имени файла, разделив вывод NUL-байтами, используя -zопцию, например, для этих файлов, содержащих пробелы, символы новой строки и символы глобуса (цитируются ls):
$ ls has*'has'$'\n''newline.bar''has space.bar''has*.bar'
Если вы не можете использовать базовое имя, как предлагается в других сообщениях, вы всегда можете использовать sed. Вот (ужасный) пример. Он не самый лучший, но он работает, извлекая искомую строку и заменяя ввод желаемой строкой.
echo '/foo/fizzbuzz.bar'| sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'
Хотя это и является ответом на исходный вопрос, эта команда полезна, когда у меня есть строки путей в файле для извлечения базовых имен и их вывода на экран.
Sangcheol Choi
2
Остерегайтесь предложенного решения perl: оно удаляет все, что находится после первой точки.
$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some
Базовое имя делает это, удаляет путь. Он также удалит суффикс, если он задан, и, если он совпадает с суффиксом файла, но вам необходимо знать суффикс, который нужно дать команде. В противном случае вы можете использовать mv и выяснить, какое новое имя должно быть другим способом.
${parameter%word}
и${parameter%%word}
в разделе соответствия конечной части.Ответы:
Вот как это сделать с помощью операторов # и% в Bash.
${x%.bar}
также может быть${x%.*}
удалить все после точки или${x%%.*}
удалить все после первой точки.Пример:
Документацию можно найти в руководстве по Bash . Посмотрите
${parameter%word}
и${parameter%%word}
раздел соответствия задней части.источник
посмотрите на команду basename:
источник
Чистый bash, сделанный в двух отдельных операциях:
Удалить путь из строки пути:
Удалите расширение из строки пути:
источник
Используя basename, я использовал следующее для достижения этой цели:
Это не требует априорных знаний о расширении файла и работает, даже если у вас есть имя файла с точками в имени файла (перед его расширением);
basename
Хотя для этого требуется программа , но это часть ядра GNU Coreutils, поэтому она должна поставляться с любым дистрибутивом.источник
fname=`basename $file .$ext`
Pure Bash путь:
Эта функциональность описана на man bash в разделе «Расширение параметров». Существует множество способов, не связанных с bash: awk, perl, sed и так далее.
РЕДАКТИРОВАТЬ: работает с точками в суффиксах файлов и не нужно знать суффикс (расширение), но не работает с точками в самом имени .
источник
Функции basename и dirname - это то, что вам нужно:
Имеет выход:
источник
mystring=$1
вместо текущего постоянного значения (которое будет подавлять несколько предупреждений, будучи уверенным, что они не содержат пробелы / символы глобуса / и т. Д.), И решите проблемы, с которыми оно связано находки?echo "basename: $(basename "$mystring")"
- таким образом, еслиmystring='/foo/*'
вы не получите*
замену со списком файлов в текущем каталоге послеbasename
завершения.Использование
basename
предполагает, что вы знаете, что такое расширение файла, не так ли?И я считаю, что различные предложения по регулярным выражениям не справляются с именем файла, содержащим более одного "."
Следующее, кажется, справляется с двойными точками. Да, и имена файлов, которые содержат "/" сами (только для ударов)
Перефразируя Паскаля: «Извините, этот скрипт такой длинный. У меня не было времени сделать его короче»
источник
В дополнение к согласованному синтаксису POSIX, используемому в этом ответе ,
как в
GNU
basename
поддерживает другой синтаксис:с тем же результатом. Разница и преимущество состоит в том, что
-s
означает-a
, что поддерживает несколько аргументов:Это даже можно сделать безопасным для имени файла, разделив вывод NUL-байтами, используя
-z
опцию, например, для этих файлов, содержащих пробелы, символы новой строки и символы глобуса (цитируютсяls
):Чтение в массив:
readarray -d
требуется Bash 4.4 или новее. Для более старых версий мы должны выполнить цикл:источник
источник
Если вы не можете использовать базовое имя, как предлагается в других сообщениях, вы всегда можете использовать sed. Вот (ужасный) пример. Он не самый лучший, но он работает, извлекая искомую строку и заменяя ввод желаемой строкой.
Что даст вам выход
источник
Остерегайтесь предложенного решения perl: оно удаляет все, что находится после первой точки.
Если вы хотите сделать это с Perl, это работает:
Но если вы используете Bash, решения с
y=${x%.*}
(или,basename "$x" .ext
если вы знаете расширение) гораздо проще.источник
Базовое имя делает это, удаляет путь. Он также удалит суффикс, если он задан, и, если он совпадает с суффиксом файла, но вам необходимо знать суффикс, который нужно дать команде. В противном случае вы можете использовать mv и выяснить, какое новое имя должно быть другим способом.
источник
Объединяя ответ с наивысшим рейтингом и ответ с наивысшим рейтингом, чтобы получить имя файла без полного пути:
источник