Ответы:
basename
из GNU coreutils может помочь вам сделать эту работу:
$ basename /root/video.mp4
video.mp4
Если вы уже знаете расширение файла, вы можете вызвать его basename
используя синтаксис basename NAME [SUFFIX]
, чтобы удалить его:
$ basename /root/video.mp4 .mp4
video
Или другой вариант будет вырезать все после последней точки, используя sed
:
$ basename /root/video.old.mp4 | sed 's/\.[^.]*$//'
video.old
Самое простое решение - удалить все до последнего появления /
:
echo /root/video.mp4 | sed 's/.*\///'
Используйте любой из следующих способов:
out_file="${in_file##*/}"
out_file="$(basename $in_file)"
out_file="$(echo $in_file | sed 's=.*/==')"
out_file="$(echo $in_file | awk -F"/" '{ print $NF }')"
пс. Вы получаете ту же строку, потому что в вашем утверждении \(.*\.\)
соответствует строке от начала до точки ( /root/video.
), а затем вы добавляете вручную.mp4
что совпадает с исходной строкой. Вы должны использовать s=.*\([^/]*\)=\1=
вместо этого.
Обновление: (первое исправлено сейчас)
Чтобы получить единственное имя файла без расширения, вы можете:
out_file="$(echo $in_file | sed 's=.*/==;s/\.[^.]*$/.new_ext/')"
out_file="$(echo $in_file | sed 's=\([^/]*\)\.[^./]*$=\1.new_ext=')"
out_file="$(echo $in_file | awk -F"/" '{ gsub (/\.[^/.]*$/,".new_ext",$NF);print $NF }'
my.file.tar.gz
.
sed
и awk
. Исправлена. Спасибо.
Одна из основ использования регулярных выражений заключается в том, что шаблоны являются жадными по своей природе при указании подстановочных знаков. Хотя ответ, предложенный @uloBasEI, безусловно, является рабочим ответом, он также требует использования команды basename. Оригинальный вопрос от @Shixons требует решения с использованием только sed.
Прежде чем продолжить, всегда полезно знать, какая версия sed является целевой. Я предполагаю, BSD (как поставляется с OSX).
Прежде всего, шаблон, предложенный в исходном вопросе, не работает, потому что он захватывает все от начала входной строки до последней точки включительно. Без якорей этот поиск поглотит все слева направо. Следовательно, сопоставляемый шаблон "/ 1" - это все, вплоть до последней точки. Даже имя файла с несколькими точками будет поглощено целиком. Не желаемый результат вообще.
Первым шагом является разработка стратегии для определения закономерностей. Здесь вы хотите избавиться от всего, что находится слева от имени файла (мы рассмотрим расширение позже):
out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"
Поиск соответствует началу строки. Он соответствует шаблону "/.*" ноль или более раз и впоследствии удаляет все. Мы печатаем совпавшие образцы с "\ 1". Мы не ищем глобально; мы ищем в начале строки, указав якорь ^.
Мы получаем лучшую ясность, включив опцию "-E", чтобы нам не пришлось избегать скобок:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"
Так что теперь у нас есть часть слева. Давайте добавим часть справа. Обратите внимание, что нам нужно сохранить левую часть как шаблон, потому что именно так мы можем указать, что она появляется ноль или более раз. Все, что мы делаем сейчас, это добавляем шаблон для части справа:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"
Мы распечатываем только второе совпадение, тем самым отбрасывая все, кроме имени файла. Но нам все равно нужно удалить расширение файла.
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"
"$" В конце не является обязательным.
Наконец, чтобы добавить новое расширение, вы просто измените его так:
out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"
Дополнительная оптимизация состоит в том, чтобы сделать первый прямой слеш необязательным для обработки относительных путей:
out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"
Я столкнулся с этим вопросом, будучи ленивым, когда искал шаблон sed для замены базового имени . Я работаю над удаленной системой, в которой не установлена эта команда.
sed 's/\.[^.]*$//'
как у вас, не удастся для (скрытых).filename
и.
и..
каталогов