Направьте вывод базового имени на замену строки

Мне нужно базовое имя файла, которое передается в качестве аргумента скрипту bash. Базовое имя должно быть лишено расширения файла. Предположим, что $1 = "/somefolder/andanotherfolder/myfile.txt", желаемый результат будет "myfile".

Текущая попытка создает промежуточную переменную, которой я хотел бы избежать:

BASE=$(basename "$1")
NOEXT="${BASE%.*}"

Моя попытка сделать это однострочным будет заключаться в передаче вывода basename. Однако я не знаю, как передать стандартный вывод для замены строки.

РЕДАКТИРОВАТЬ: это должно работать для нескольких расширений файлов с возможной разной длиной, поэтому попытка замены строки, как указано выше.


person stee    schedule 01.07.2020    source источник
comment
Поставьте точку с запятой между ними, и это станет однострочным.   -  person oguz ismail    schedule 01.07.2020
comment
Пожалуйста, посмотрите на man basename.   -  person Cyrus    schedule 01.07.2020
comment
Спасибо. Для первого ответа @oguzismail: как заменить имя переменной BASE, если оно однострочное?   -  person stee    schedule 01.07.2020
comment
@KamilCuk Это работает только для одного конкретного окончания файла (в данном случае txt).   -  person stee    schedule 01.07.2020
comment
@ Сайрус Я сделал. Если я что-то упустил, это невозможно только с базовым именем.   -  person stee    schedule 01.07.2020
comment
Взгляните на этот ответ stackoverflow.com/a/965072/11934850 Петеша на аналогичный вопрос.   -  person Sascha Doerdelmann    schedule 01.07.2020
comment
@KamilCuk: это предложение подразумевает, что мы уже знаем, что расширение .txt. Из кода, предоставленного OP, в частности, из расчета NOEXT, я бы предположил, что расширение может быть любым.   -  person user1934428    schedule 01.07.2020
comment
@SaschaDoerdelmann Ответ, который вы упомянули, объясняет, как это сделать в два этапа, что является текущим подходом, который я описал в вопросе.   -  person stee    schedule 01.07.2020


Ответы (4)


Почему не Зойдберг? Э-э-э... Я имел в виду, почему бы не удалить расширение перед переходом к базовому имени?

basename "${1%.*}"

Если, конечно, у вас нет путей к каталогам с точками, вам придется использовать базовое имя раньше и удалить расширение позже:

echo $(basename "$1") | awk 'BEGIN { FS = "." }; { print $1 }'

Решение awk удалит все после первой точки в имени файла.

Существует решение на основе регулярных выражений, которое использует sed для удаления только расширения после последней точки, если оно существует:

echo $(basename "$1") | sed 's/\(.*\)\..*/\1/'

Это можно даже улучшить, если вы уверены, что у вас есть буквенно-цифровые расширения из 3-4 символов (например: mp3, mpeg, jpg, txt, json...)

echo $(basename "$1") | sed 's/\(.*\)\.[[:alnum:]]\{3\}$/\1/'
person Orsiris de Jong    schedule 01.07.2020
comment
Мне очень нравится первый вариант ради простоты и читабельности. Однако пути, включающие точки, могут быть проблемой. - person stee; 01.07.2020
comment
На самом деле, я только что попробовал это с путем, содержащим имена папок, используя точки, и это сработало. - person stee; 01.07.2020
comment
Действительно, он будет работать даже с путями, содержащими точки, но только если ваше имя файла тоже содержит точку. если $1= '/some.dir/myfile', он будет обрезан по первой обнаруженной точке в конце. Вторая версия просто более безопасна в использовании, даже если она уродливее;) Но bash в любом случае не самый красивый скриптовый язык, IMO;) - person Orsiris de Jong; 01.07.2020
comment
Ты прав. На оборотной стороне медали: решение awk не работает должным образом, если само имя файла содержит точку перед окончанием файла. - person stee; 01.07.2020
comment
Итак, после некоторого размышления кажется, что самым чистым, но уродливым решением может быть следующее: echo $(basename "$1") | rev | cut -d"." -f 2- | rev Он получит базовое имя и удалит все после последнего . базового имени. - person stee; 01.07.2020
comment
Это действительно много уродства. Я добавил решение на основе sed, которое использует регулярные выражения для ограничения расширений файлов. - person Orsiris de Jong; 02.07.2020

Как насчет этого?

NEXT="$(basename -- "${1%.*}")"

Тестирование:

set -- '/somefolder/andanotherfolder/myfile.txt'
NEXT="$(basename -- "${1%.*}")"
echo "$NEXT"

myfile

В качестве альтернативы:

set -- "${1%.*}"; NEXT="${1##*/}"
person Léa Gris    schedule 01.07.2020

Как насчет:

$ [[ $var =~ [^/]*$ ]] && echo ${BASH_REMATCH%.*}
myfile
person James Brown    schedule 01.07.2020

person    schedule
comment
избегайте промежуточной переменной;) - person alecxs; 01.07.2020
comment
Ха! подлый ;p - person stee; 01.07.2020