Як видалити останні n n символів із рядка в Bash?


202

У мене є змінна varв сценарії Bash, що містить рядок, наприклад:

echo $var
"some string.rtf"

Я хочу видалити останні 4 символи цього рядка і призначити результат новій змінній var2, так що

echo $var2
"some string"

Як я можу це зробити?


Відповіді:


15

По-перше, ви повинні бути чіткими щодо того, чого ви хочете. Якщо ви знаєте, що рядок закінчується, .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")- це, мабуть, найкоротший варіант.


240

Ви можете зробити так:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"

9
баш 4+ я думаю.
Ітан Рейснер

69
Це bash4+, але в більш ранній версії можна використовувати трохи довший ${v::${#v}-4}.
чепнер

8
Не працював для мене, Баш каже: "Погана заміна"
Іван Марянович

15
чомусь у zsh ${v::-4}croaks "zsh: очікується закриття дужки". Але відповідь @fredtantini нижче ${v:0:-4}працює добре.
П’єр Д

6
Помилка: -2: вираз підрядки <0
Едвард

172

Щоб видалити чотири символи з кінця рядка, використовуйте ${var%????}.

Щоб видалити все після остаточного .використання ${var%.*}.


12
Чистий відповідь оболонки, і вона буде працювати в BASH 3.x, що знайдено в багатьох системах, які відмовилися від впровадження BASH 4.x через проблеми з ліцензуванням.
David W.

1
Це круто, оскільки він міцний проти отримання коротших струн; Варіанти зміщення індексу тоді не вдається.
Рафаель

працює в басі 3.2.25 - найкраща відповідь - саме те, що я шукав
capser

Відмінна відповідь. Як щодо видалення на передній частині рядка?
користувач2023370

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 /% Шаблон / Заміна}

Якщо суфікс var збігається з шаблоном, замініть Заміна на шаблон.

Отже, ви можете зробити:

~$ 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}


len=${#var}; echo ${var::len-4}можна скоротити до echo ${var:0:-4}:-) EDIT: або як вказував @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?
бекко

це добре, тому що він працює на одному рядку, як цей ... | sed 's /. \ {4 \} $ //'. Можна використовувати без використання змінних
Sam

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 додав підтримку негативної підрядки


Це набагато більш багатослівно, ніж сумісна з Борном проста заміна шаблону, як у відповіді Ітана Рейснера.
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%.*}"

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

% означає рубати,. це те, що ти рубаєш, * це підстановка

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.