Обрезка всех персонажей после последнего /


14

Как мне вырезать все символы после последнего '/'?

Этот текст

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

должен вернуться

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

Хороший вопрос, я только что понял, что мы не поняли вопрос по-
разному

3
Команды basenameи dirnameсделать это уже.
Майкл Хэмптон

Я не думаю, что редактировать # 5, чтобы вопрос был правильным. Использование слова «вырезать» может быть неоднозначным; если вы что-то режете, вы отбрасываете эту часть или оставляете только это? Однако предыдущая формулировка «и опускать то, что есть перед /» была однозначной. Это было изменено на противоположное.
egmont

@egmont само слово «вырезать» было перенесено из оригинала: «Мне нужно вырезать только символы после последнего /» стало «Как вырезать все символы после последнего« / »?» который является изменением формулировки, которая разумно сохраняет значение, ИМО. Во всяком случае, я чувствовал, что часть «пропустить то, что ...» неоднозначна: примеры, кажется, сохраняют то, что есть до /. Во всяком случае, этот пример проясняет ситуацию.
Муру

@muru Я говорю о редактировании, которое добавило примеры, а не о ваших изменениях.
egmont

Ответы:


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
Я отправил предлагаемое изменение для использования | вместо /. Если вам это не нравится, я предлагаю вам «отклонить и отредактировать» его и изменить «начало» на «начало». (Отклонить + изменить, потому что таким образом он не будет одобрен роботом-утверждающим. В качестве альтернативы просто откатите изменение, если оно получено, и вам это не понравилось.)
Мартин Боннер поддерживает Monica

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: потому что dirname и basename не работают на stdin, поэтому cat text | basenameне будут работать. Таким образом, правильное решение вопроса OP с использованием 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/

Короче, как отметил Федорки в комментариях:

$ 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бла-бла.
Федорки

3

Добавление к ответу egmont, потому что вопрос был отредактирован ...

Используйте --complement, если вы хотите удалить первое поле с -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

Кроме того, не совсем ясен вопрос о том, что должно происходить с входными данными, не содержащими косую черту. хххх => хххх или хххх => ничего


Вы можете предложить изменить его: askubuntu.com/posts/1010356/edit
muru

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

@SergiyKolodyazhnyy кто-нибудь может предложить правки.
Муру

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

2
-f2-это более простая форма для -f1 --complement.
egmont
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.