Вирізання всіх символів після останнього /


14

Як вирізати всі символи після останнього "/"?

Цей текст

xxxx/x/xx/xx/xxxx/x/yyyyy
xxx/xxxx/xxxxx/yyy

повинен повернутися

xxxx/x/xx/xx/xxxx/x
xxx/xxxx/xxxxx

Добре запитання, я щойно зрозумів, що ми не зрозуміли це питання однаково
Félicien

3
Команди basenameі dirnameзробіть це вже.
Майкл Хемптон

Я не думаю, що редагування №5 до питання було правильним. Використання слова "вирізати" може бути неоднозначним; якщо ти щось ріжеш, викидаєш цю частину, чи зберігаєш лише це? Однак попереднє формулювання "і пропустити те, що є перед /" було однозначним. Це було змінено на протилежність.
Егмонт

@egmont саме слово "вирізати" було перенесено з оригіналу: "Мені потрібно вирізати лише символи після останнього /" стало "Як я вирізати всі символи після останнього" / "?" що є зміною фразування, що розумно зберігає значення, ІМО. Якщо що-небудь, я вважав, що частина "опустити те, що є ..." неоднозначно: приклади, здається, зберігають те, що є раніше /. Приклад, у будь-якому разі, це дає зрозуміти.
муру

@muru Я говорю про редагування, яке додало приклади, а не вашу редакцію.
Егмонт

Відповіді:


15

Якщо ви хочете отримати "вирізану частину"

yyy
yyyyy

Можна використовувати

sed 's|.*/||' 

напр.

echo "xxx/xxxx/xxxxx/yyy" | sed 's|.*/||'
echo "xxxx/x/xx/xx/xxxx/x/yyyyy" | sed 's|.*\/||'

вихід

yyy
yyyyy

(Примітка. Для цього використовується можливість sed використовувати роздільник, відмінний від /, у цьому випадку | у команді s)


Якщо ви хочете отримати початок рядка:

xxx/xxxx/xxxxx
xxxx/x/xx/xx/xxxx/x

Можна використовувати

sed 's|\(.*\)/.*|\1|'

напр.

echo "xxx/xxxx/xxxxx/yyy" | sed 's|\(.*\)/.*|\1|'
echo "xxxx/x/xx/xx/xxxx/x/yyyyy" | sed 's|\(.*\)/.*|\1|'

вихід

xxx/xxxx/xxxxx
xxxx/x/xx/xx/xxxx/x

6
Привіт, у цьому випадку ви можете змінити роздільник, наприклад, #замість /. Також ви можете використовувати опцію , -rякщо ви не хочете , щоб уникнути `\` кожного спеціального символу: sed -r 's#(^.*)/.*$#\1#'.
pa4080

1
Я подав запропоновану редакцію для використання | замість /. Якщо вам це не подобається, я пропоную вам "відхилити та відредагувати" його та змінити "початок" на "початок". (Відхиліть + редагувати, тому що вони не отримають схвалення роботодавцями. Крім того, просто поверніть зміни, якщо вони були схвалені, і вам це не сподобалось.)
Мартін Боннер підтримує Моніку

18

Якщо ви виріжете від кінців рядків, dirnameмогли б відповідати всім вимогам:

$ dirname xxxx/x/xx/xx/xxxx/x/yyyyy
xxxx/x/xx/xx/xxxx/x
$ _

Якщо ви намагаєтесь ізолювати останню частину рядка, використовуйте echo /$(basename "$str").

$ str=xxxx/x/xx/xx/xxxx/x/yyyyy
$ echo /$(basename "$str")
/yyyyy
$ _

3
Чесно кажучи, чому хтось або запропонував би, або прийняти відповідь, що стосується sed (або awk, чи будь-який інший подібний метод) замість того, щоб просто скористатися утилітами, встановленими в ОС, не за межами мене.
Auspex

@Auspex я припускаю , що це просто тому , що dirnameі basenameНЕ так широко відомі, але sedі awkє.
Волкер Зігель

@Auspex: Оскільки ім'я та ім'я користувача не працюють на stdin, тому cat text | basenameне працюватимуть. Таким чином, правильне вирішення питання ФП, використовуючи dirnameі basenameвключатиме в себе і xargsт.д.
Pod

16

Розширення параметра в bash

У bashцьому випадку ви можете використовувати розширення параметрів

  • ${parameter%word}де wordє/*
  • ${parameter##word}де wordє*/

Приклади:

Видаліть останню частину

$ asdf="xxx/xxxx/xxxxx/yyy"
$ echo ${asdf%/*}
xxx/xxxx/xxxxx

Це описано в man bash:

${parameter%word}
${parameter%%word}
      Remove matching suffix pattern.  The word is expanded to produce
      a pattern just as in pathname expansion.  If the pattern matches
      a  trailing portion of the expanded value of parameter, then the
      result of the expansion is the expanded value of parameter  with
      the  shortest  matching  pattern (the ``%'' case) or the longest
      matching pattern (the ``%%'' case) deleted.  If parameter  is  @
      or  *,  the  pattern  removal operation is applied to each posi‐
      tional parameter in turn, and the  expansion  is  the  resultant
      list.   If  parameter is an array variable subscripted with @ or
      *, the pattern removal operation is applied to  each  member  of
      the array in turn, and the expansion is the resultant list.

Видаліть усі, крім останньої частини

$ asdf="xxx/xxxx/xxxxx/yyy"
$ echo ${asdf##*/}
yyy

Ви можете додати косу рису так

$ echo /${asdf##*/}
/yyy

щоб отримати саме те, що ви хотіли в одному конкретному екземплярі відповідно до відредагованого питання. Але питання було відредаговано декількома людьми після цього, і нелегко дізнатися, що ви хочете зараз.

Це описано в man bash:

${parameter#word}
${parameter##word}
      Remove matching prefix pattern.  The word is expanded to produce
      a pattern just as in pathname expansion.  If the pattern matches
      the  beginning of the value of parameter, then the result of the
      expansion is the expanded value of parameter with  the  shortest
      matching  pattern  (the ``#'' case) or the longest matching pat‐
      tern (the ``##'' case) deleted.  If parameter is  @  or  *,  the
      pattern  removal operation is applied to each positional parame‐
      ter in turn, and the expansion is the resultant list.  If param‐
      eter  is  an array variable subscripted with @ or *, the pattern
      removal operation is applied to each  member  of  the  array  in
      turn, and the expansion is the resultant list.

10

Інший спосіб - використовувати grepлише для відображення останньої косої риски за рядком і того, що слід за нею:

$ grep -o '/[^/]*$' example.txt
/yyy
/yyyyy

Пояснення:

-oвказує grepпоказувати лише відповідну частину рядка замість цілого рядка.

Шаблон /[^/]*$відповідає буквальній косою рисою, /за якою слідує будь-який символ, за винятком косої риски [^/]будь-яку кількість разів *до кінця рядка $.


8

Тільки тому, що інші опублікували більше «розумних» відповідей, ось дещо нерозумний:

rev | cut -d/ -f1 | rev

revповертає символи в кожному рядку, наприклад, abcd/ef/gстає g/fe/dcba. Потім cutвирізається перший сегмент. Нарешті це знову перевернуто.


2
Незважаючи на негідність цієї відповіді, особливо через сантехніку, мені подобається ця відповідь :) Продовжуйте гойдатися, +1
Сергій Колодяжний,

Домовились - не розумно, а погано!
Волкер Зігель

3

Класичне рішення з awk, яке розглядає /як розділювач поля як для введення, так і для виведення та встановлює останнє поле порожнім рядком (що насправді є "перенаправленням" кількості NFзмінних полів ):

$ echo "xxx/xxxx/xxxxx/yyy"|awk  'BEGIN{OFS=FS="/"};{$NF="";print $0}'
xxx/xxxx/xxxxx/

Коротше, як в коментарях зазначив fedorqui :

$ echo "xxx/xxxx/xxxxx/yyy"|awk  'BEGIN{OFS=FS="/"};NF--'
xxx/xxxx/xxxxx/

Варіантом цього може бути те, щоб поставити шлях у awkсередовище виконання, що дозволить заощадити на сантехніці, але зробить awkчастину більш багатослівною:

mypath="xxx/xxxx/xxxxx/yyy" awk  'BEGIN{OFS=FS="/"; sub(/\/([^\/]*)$/,"",ENVIRON["mypath"]);print(ENVIRON["mypath"]) };'

1
Занадто багатослівний, чому б не просто NF--? Таким чином, ви отримали благу благу print.
fedorqui

3

Додавання відповіді Егмонта, оскільки питання було відредаговано ...

Використовуйте --доповнення, якщо ви хочете видалити перше поле з -f1 .

echo "xxxx/x/xx/xx/xxxx/x/yyyyy"|rev|cut -d/ -f1 --complement|rev
xxxx/x/xx/xx/xxxx/x

echo "xxxx/x/xx/xx/xxxx/x/yyyyy"|rev|cut -d/ -f1|rev
yyyyy

Крім того, питання не зовсім зрозуміло, що має відбуватися із входами, які не містять косої риски. xxxx => xxxx або xxxx => нічого


Ви можете запропонувати його змінити: askubuntu.com/posts/1010356/edit
вчера

@muru OP - це 1 користувач. Не надається привілей на редагування в 2k? askubuntu.com/help/privileges/edit
Сергій Колодяжний

@SergiyKolodyazhnyy будь-хто може запропонувати зміни.
муру

+1 - Я раніше не помічав цього --complementваріанту, а сторінка людини кругла. Доповнення означає доповнення. Я знайшов чудовий підручник, який висвітлює його на yourownlinux.com/2015/05/… Це як -vу grep. Дайте мені все, крім того, що було відповідне.
Джо

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