Как получить только имя файла с помощью sed


17

Как я могу получить только имя файла, используя sed? У меня есть это

out_file=$(echo $in_file|sed "s/\(.*\.\).*/\1mp4/g")

Но я тоже понимаю путь /root/video.mp4и хочу только video.mp4.

Ответы:


26

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

3
Использование, sed 's/\.[^.]*$//'как у вас, не удастся для (скрытых) .filenameи .и ..каталогов
Peter.O

9

Самое простое решение - удалить все до последнего появления /:

echo /root/video.mp4 | sed 's/.*\///'


5

Используйте любой из следующих способов:

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 }'

Но с любым из этих методов я получаю имя файла с форматом, и мне нужно получить только имя файла и вручную установить новый формат.
Шиксонс

Ах, это имеет смысл. Я обновил свой ответ.
Раш

@rush: будут крайние случаи, например, для файла с именем my.file.tar.gz.
Успехов

@donothingsuccessfully был недостающий символ точки в последнем sedи awk. Исправлена. Спасибо.
Раш

4

Одна из основ использования регулярных выражений заключается в том, что шаблоны являются жадными по своей природе при указании подстановочных знаков. Хотя ответ, предложенный @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 для замены базового имени . Я работаю над удаленной системой, в которой не установлена ​​эта команда.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.