Как удалить последние n символов из строки в Bash?

202

У меня есть переменная var в скрипте Bash, содержащая строку, например:

echo $var
"some string.rtf"

Я хочу удалить последние 4 символа этой строки и назначить результат новой переменной var2, чтобы

echo $var2
"some string"

Как я могу это сделать?

becko
источник
1
Дубликат экстракта-подстроки в bash
Håkon Hægland

Ответы:

16

Во-первых, вы должны четко указать, что вы хотите. Если вы знаете, что строка заканчивается, .rtfи вы хотите удалить .rtf, вы можете использовать var2=${var%.rtf}. Если вы не знаете, что такое суффикс, но хотите удалить все, начиная с последнего ., тогда вы можете использовать var2=${var%.*}. Если вы хотите только сохранить все до первого ., вы можете использовать var2=${var%%.*}. Эти два последних варианта имеют одинаковый результат, если есть только один период, но если их может быть больше одного, вы должны решить, какой вы хотите.

Если вы действительно хотите всегда удалять точное количество символов, вот несколько вариантов.

Вы указали bash специально, поэтому мы начнем со встроенных команд bash. Дольше всего работал тот же синтаксис удаления суффиксов, который я использовал выше: чтобы удалить четыре символа, используйте var2=${var%????}. Вам нужно один вопросительный знак на каждый удаленный символ, так что это становится громоздким для больших длин подстрок.

Немного новее извлечения подстроки: var2=${var::${#var}-4}. Здесь вы можете поставить любое число вместо, 4чтобы удалить другое количество символов. (Символ ${#var}заменяется длиной строки, поэтому на самом деле запрашивается оставить первые (длина - 4) символа.)

Более новые версии bash (в частности, 4+, что означает, что та, которая поставляется с MacOS, не будет работать) позволяют упростить это до просто var2=${var::-4}.

Если вы на самом деле не используете bash, а какую-то другую оболочку типа POSIX, удаление суффикса все равно будет работать, даже в простой старой черте (где ни один из остальных не будет). В Zsh, все они работают , но вы должны поставить 0между двоеточием: и var2=${var:0:-4}т.д. В КШ, вам нужно 0 , а также использовать явное выражение длиной 4: var2=${var:0:${#var}-4}.

Конечно, вы можете использовать подстановку команд, чтобы сделать это с помощью служебной программы; Есть много, которые будут работать, но что-то вроде var2=$(cut -c -4 <<<"$var"), вероятно, самый короткий вариант.

Марк Рид
источник
241

Вы можете сделать так:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"
фе
источник
9
Баш 4+ я думаю.
Этан Рейснер,
69
Это bash4+, но в более ранней версии вы можете использовать немного дольше ${v::${#v}-4}.
chepner
8
У меня ничего не вышло, Баш говорит: «Плохая замена»
Иван Марьянович,
15
почему-то в зш ${v::-4}хрипит "зш: закрывающая скобка ожидается". Но ответ @fredtantini ниже ${v:0:-4}работает отлично.
Пьер Д
6
Ошибка с: -2: выражение подстроки <0
Эдвард
174

Для удаления четырех символов из конца строки используйте ${var%????}.

Чтобы удалить все после окончательного .использования ${var%.*}.

Этан Рейснер
источник
12
Ответ Pure Shell, и он будет работать в BASH 3.x, который встречается во многих системах, которые отказались от реализации BASH 4.x из-за проблем с лицензированием.
Дэвид В.
1
Это круто, так как оно устойчиво к получению более коротких струн; варианты смещения индекса потерпят неудачу тогда.
Рафаэль
работает в Bash 3.2.25 - лучший из возможных ответов - именно то, что я искал
capser
Отличный ответ. Как насчет удаления в начале строки?
user2023370
3
@ user2023370 Консультирование по документации должно показать, что для этого есть соответствующая замена параметров ${var#????}.
tripleee
48

Что сработало для меня:

echo "hello world" | rev | cut -c5- | rev
# hello w

Но я использовал его для обрезки строк в файле, поэтому он выглядит неловко. Реальное использование было:

cat somefile | rev | cut -c5- | rev

cutтолько уводит вас от обрезки с некоторой начальной позиции, что плохо, если вам нужны строки переменной длины. Таким образом, это решение переворачивает ( rev) строку, и теперь мы относимся к ее конечной позиции, затем используем, cutкак уже упоминалось, и возвращаем (снова rev) ее обратно в исходный порядок.

Реут Шарабани
источник
Это не правильно и не является ответом на то, что спрашивают. revпереворачивает строки, а не строки. echo $SOME_VAR | rev | ...вероятно, не будет вести себя так, как можно было бы ожидать.
Мохаммад Насирифар
2
@Mohammad Из-за сломанной со ссылкой, что это одна строка.
tripleee
38

Использование расширения переменной / замена подстроки :

$ {Вар /% шаблон / замена}

Если суффикс var соответствует Pattern, замените шаблон на Pattern.

Так что вы можете сделать:

~$ echo ${var/%????/}
some string

С другой стороны,

Если у вас всегда одинаковые 4 буквы

~$ echo ${var/.rtf/}
some string

Если это всегда заканчивается на .xyz:

~$ echo ${var%.*}
some string

Вы также можете использовать длину строки:

~$ len=${#var}
~$ echo ${var::len-4}
some string

или просто echo ${var::-4}

fredtantini
источник
len=${#var}; echo ${var::len-4}может быть сокращено до echo ${var:0:-4}:-) РЕДАКТИРОВАТЬ: или, как указал @iyonizer, просто echo ${var::-4}...
anishsane
26

Вы могли бы использовать sed,

sed 's/.\{4\}$//' <<< "$var"

Пример:

$ var="some string.rtf"
$ var1=$(sed 's/.\{4\}$//' <<< "$var")
$ echo $var1
some string
Авинаш Радж
источник
1
и как мне назначить результат var2?
Becko
это хорошо, потому что он работает на одной строке, как это ... | sed 's /. \ {4 \} $ //'. Может использоваться без использования переменных
Сэм
3

Я попробовал следующее, и это сработало для меня:

#! /bin/bash

var="hello.c"
length=${#var}
endindex=$(expr $length - 4)
echo ${var:0:$endindex}

Вывод: hel

Прия Джайн
источник
1

Надеюсь, что приведенный ниже пример поможет,

echo ${name:0:$((${#name}-10))} -> ${name:start:len}

  • В приведенной выше команде имя является переменной.
  • start является отправной точкой строки
  • len это длина строки, которая должна быть удалена.

Пример:

    read -p "Enter:" name
    echo ${name:0:$((${#name}-10))}

Вывод:

    Enter:Siddharth Murugan
    Siddhar

Примечание: в Bash 4.2 добавлена ​​поддержка отрицательной подстроки

Сиддхарт Муруган
источник
Это гораздо более многословно, чем Bourne-совместимая простая замена шаблона, как в ответе Etan Reisner.
tripleee
0

Это сработало для меня, рассчитав размер строки.
Вам просто нужно отобразить значение, которое нужно вернуть, и затем сохранить его, как показано ниже

removechars(){
        var="some string.rtf"
        size=${#var}
        echo ${var:0:size-4}  
    }
    removechars
    var2=$?

какая-то строка

Саурабх
источник
0

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

Пример:

basename -s .rtf "some string.rtf"

Это вернет "некоторую строку"

Если вы не знаете суффикс и хотите удалить все после и включая последнюю точку:

f=file.whateverthisis
basename "${f%.*}"

выводит "файл"

% означает рубить. это то, что вы режете, * подстановочный знак

Грета
источник