Как удалить суффикс файла и путь из строки пути в Bash?
Учитывая путь к строковому файлу, например /foo/fizzbuzz.bar
, как бы я использовал bash для извлечения только части fizzbuzz
из указанной строки?
Ответы
Ответ 1
Здесь, как это сделать С# и% операторами в Bash.
$ x="/foo/fizzbuzz.bar"
$ y=${x%.bar}
$ echo ${y##*/}
fizzbuzz
${x%.bar}
также может быть ${x%.*}
, чтобы удалить все после точки или ${x%%.*}
, чтобы удалить все после первой точки.
Пример:
$ x="/foo/fizzbuzz.bar.quux"
$ y=${x%.*}
$ echo $y
/foo/fizzbuzz.bar
$ y=${x%%.*}
$ echo $y
/foo/fizzbuzz
Документацию можно найти в Bash руководстве. Найдите ${parameter%word}
и ${parameter%%word}
раздел соответствия конечной части.
Ответ 2
посмотрите на команду basename:
NAME=$(basename /foo/fizzbuzz.bar .bar)
Ответ 3
Чистый bash, выполненный в двух отдельных операциях:
-
Удалите путь из строки пути:
path=/foo/bar/bim/baz/file.gif
file=${path##*/}
#$file is now 'file.gif'
-
Удалить расширение из строки пути:
base=${file%.*}
#${base} is now 'file'.
Ответ 4
Используя базовое имя, я использовал для этого следующее:
for file in *; do
ext=${file##*.}
fname=`basename $file $ext`
# Do things with $fname
done;
Это не требует априорного знания расширения файла и работает даже тогда, когда у вас есть имя файла, в котором есть точки в имени файла (перед его расширением); он действительно требует программы basename
, хотя, но это часть GNU coreutils, поэтому он должен поставляться с любым дистрибутивом.
Ответ 5
Чистый bash способ:
~$ x="/foo/bar/fizzbuzz.bar.quux.zoom";
~$ y=${x/\/*\//};
~$ echo ${y/.*/};
fizzbuzz
Эта функция объясняется man bash в разделе "Расширение параметров". Не существует bash способов: awk, perl, sed и т.д.
EDIT: работает с точками в суффиксах файлов и не нуждается в суффиксе (расширении), но не работает с точками в самом имени.
Ответ 6
Функции basename и dirname - это то, что вам нужно:
mystring=/foo/fizzbuzz.bar
echo basename: $(basename "${mystring}")
echo basename + remove .bar: $(basename "${mystring}" .bar)
echo dirname: $(dirname "${mystring}")
Имеет выход:
basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo
Ответ 7
perl -pe 's/\..*$//;s{^.*/}{}'
Ответ 8
Использование basename
предполагает, что вы знаете, что такое расширение файла, не так ли?
И я считаю, что различные предложения регулярного выражения не справляются с именем файла, содержащим более одного..
Следующее, похоже, справляется с двойными точками. О, и имена файлов, которые содержат "/" сами (только для ударов)
Перефразируя Pascal, "Извините, этот script так длинный. У меня не было времени, чтобы сделать его короче"
#!/usr/bin/perl
$fullname = $ARGV[0];
($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
print $basename . "\n";
Ответ 9
Если вы не можете использовать basename, как указано в других сообщениях, вы всегда можете использовать sed. Вот пример (уродливый). Это не самый большой, но он работает, извлекая нужную строку и заменяя входную строку требуемой строкой.
echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'
Что вы получите на выходе
FizzBuzz
Ответ 10
В дополнение к согласованному синтаксису POSIX, используемому в этом ответе,
basename string [suffix]
как в
basename /foo/fizzbuzz.bar .bar
basename
GNU поддерживает другой синтаксис:
basename -s .bar /foo/fizzbuzz.bar
с тем же результатом. Разница и преимущество в том, что -s
подразумевает -a
, который поддерживает несколько аргументов:
$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar
fizzbuzz
foobar
Это даже можно сделать именем файла -s afe, разделив вывод с помощью байтов NUL с помощью опции -z
, например, для этих файлов, содержащих пробелы, символы новой строки и символы глобуса (цитируемые ls
):
$ ls has*
'has'$'\n''newline.bar' 'has space.bar' 'has*.bar'
Чтение в массив:
$ readarray -d $'\0' arr < <(basename -zs .bar has*)
$ declare -p arr
declare -a arr=([0]=$'has\nnewline' [1]="has space" [2]="has*")
readarray -d
требует Bash 4.4 или новее. Для более старых версий мы должны выполнить цикл:
while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)
Ответ 11
Остерегайтесь предлагаемого решения perl: он удаляет что-либо после первой точки.
$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some
Если вы хотите сделать это с помощью perl, это работает:
$ echo some.file.with.dots | perl -pe 's/(.*)\..*$/$1/;s{^.*/}{}'
some.file.with
Но если вы используете Bash, решения с y=${x%.*}
(или basename "$x" .ext
, если вы знаете расширение) намного проще.
Ответ 12
Базовое имя делает это, удаляет путь. Он также удалит суффикс, если он указан, и если он совпадает с суффиксом файла, но вам нужно будет знать суффикс, который нужно передать команде. В противном случае вы можете использовать mv и выяснить, какое новое имя должно быть каким-то другим способом.
Ответ 13
Сочетание ответа с наивысшим рейтингом с ответом второго сверху, чтобы получить имя файла без полного пути:
$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
Ответ 14
Информацию вы можете найти в Bash manual, найдите ${parameter%word}
и ${parameter%%word}
в разделе соответствия конечной части.