Указанные имена файлов, такие как:
/the/path/foo.txt
bar.txt
Я надеюсь получить:
foo
bar
Почему это не работает?
#!/bin/bash
fullfile=$1
fname=$(basename $fullfile)
fbname=${fname%.*}
echo $fbname
Какой правильный способ сделать это?
Вам не нужно вызывать внешнюю команду basename
. Вместо этого вы можете использовать следующие команды:
$ s=/the/path/foo.txt
$ echo ${s##*/}
foo.txt
$ s=${s##*/}
$ echo ${s%.txt}
foo
$ echo ${s%.*}
foo
Обратите внимание, что это решение должно работать во всех недавних (post 2004) POSIX-совместимых оболочках (например, bash
, dash
, ksh
и т.д.).
Источник: Командный язык оболочки 2.6.2 Расширение параметров
Подробнее о bash Строковые манипуляции: http://tldp.org/LDP/LG/issue18/bash.html
${s##*/}
) описаны здесь linuxgazette.net/18/bash.html
Команда basename имеет два разных вызова; в одном вы указываете только путь, и в этом случае он дает вам последний компонент, в то время как в другом вы также указываете суффикс, который он удалит. Таким образом, вы можете упростить код примера, используя второй вызов basename. Кроме того, будьте осторожны, чтобы правильно процитировать вещи:
fbname=$(basename "$1" .txt) echo "$fbname"
basename
не поддерживает подстановочные знаки. Предоставление второго аргумента удалит только эту точную буквальную строку с конца.
Комбинация basename и cut работает отлично, даже в случае двойного окончания, например .tar.gz
:
fbname=$(basename "$fullfile" | cut -d. -f1)
Было бы интересно, если это решение нуждается в меньшей арифметической мощности, чем Bash Расширение параметров.
$(..)
- так что это становится: fbname=$(basename "$fullfile" | cut -d. -f1)
Чистое bash
, no basename
, переменное жонглирование. Задайте строку и echo
:
s=/the/path/foo.txt
echo ${s//+(*\/|.*)}
Вывод:
foo
Примечание: параметр bash
extglob должен быть "on", (по умолчанию Ubuntu it "on"), если это не так:
shopt -s extglob
Прогулка по ${s//+(*\/|.*)}
:
${s
- начать с $s.//
заменить каждый экземпляр шаблона.+(
соответствуют одному или нескольким спискам шаблонов в скобках.*\/
соответствует чему-либо перед /
. (1-й шаблон)|
Или. (разделитель рисунков.).*
соответствует чем-либо после .
. (2-й шаблон))
список концевых шаблонов.}
расширение концевого параметра - поскольку там нет /
(который должен предшествовать замене строки), сопоставленные шаблоны удаляются.Релевантный man bash
фон:
${parameter/pattern/string} Pattern substitution. The pattern is expanded to produce a pat‐ tern just as in pathname expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with #, it must match at the begin‐ ning of the expanded value of parameter. If pattern begins with %, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / fol‐ lowing pattern may be omitted. If parameter is @ or *, the sub‐ stitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.
If the extglob shell option is enabled using the shopt builtin, several extended pattern matching operators are recognized. In the following description, a pattern-list is a list of one or more patterns separated by a |. Composite patterns may be formed using one or more of the fol‐ lowing sub-patterns: ?(pattern-list) Matches zero or one occurrence of the given patterns *(pattern-list) Matches zero or more occurrences of the given patterns +(pattern-list) Matches one or more occurrences of the given patterns @(pattern-list) Matches one of the given patterns !(pattern-list) Matches anything except one of the given patterns
Вот еще один (более сложный) способ получения имени файла или расширения, сначала используйте команду rev
для инвертирования пути к файлу, вырезанного из первого .
, а затем снова инвертируйте путь к файлу, например:
filename=`rev <<< "$1" | cut -d"." -f2- | rev`
fileext=`rev <<< "$1" | cut -d"." -f1 | rev`
<<<
doohickeys - что это?
Здесь есть oneliners:
$(basename ${s%.*})
$(basename ${s} .${s##*.})
Мне это нужно, так же, как попросили bongbang и w4etwetewtwet.
Если вы хотите хорошо играть с файловыми путями Windows (под Cygwin), вы также можете попробовать следующее:
fname=${fullfile##*[/|\\]}
Это будет учитывать разделители обратной косой черты при использовании BaSH в Windows.
Просто альтернатива, которую я придумал, чтобы извлечь расширение, используя сообщения в этом потоке с моей собственной небольшой базой знаний, которая была мне более знакома.
ext="$(rev <<< "$(cut -f "1" -d "." <<< "$(rev <<< "file.docx")")")"
Примечание. Просьба сообщить о моем использовании котировок; это сработало для меня, но я мог бы что-то упустить при их правильном использовании (я, вероятно, использую слишком много).
rev <<< file.docx | cut -f1 -d. | rev
просто без кавычек и без вложенных вложенных оболочек. Также я не думаю, что вышеупомянутое может работать вообще.
Используйте команду basename. Его manpage здесь: http://unixhelp.ed.ac.uk/CGI/man-cgi?basename
basename
, но это не его проблема.
$1
на самом деле то, что вы думаете. Тем не менее, он может быть разделен по словам и расширению имени файла из-за неправильного цитирования .