在最后一个/之后剪切所有字符


14

如何剪切最后一个'/'之后的所有字符?

本文

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

应该回来

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

好问题,我只是意识到我们不明白的问题以同样的方式
菲利

3
命令basenamedirname已执行此操作。
迈克尔·汉普顿

我认为问题的编辑#5不正确。使用“ cut”一词可能不明确;如果裁切掉了,会丢掉那一部分,还是只保留那一部分?但是,前面的措词“并省略/之前的内容”是明确的。相反。
egmont

@egmont单词“ cut”本身是从原语中继承过来的:“我只需要剪切最后一个/字符之后的字符,就变成了“如何剪切最后一个'/'之后的所有字符?” 这是措辞上的变化,合理保留了IMO的含义。如果有的话,我觉得“省略……是什么”部分是模棱两可的:这些示例似乎保留了之前的内容/。无论如何,这个例子很清楚。
大师

@muru我正在谈论添加示例的编辑,而不是您的编辑。
egmont

Answers:


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我猜它只是因为dirnamebasename并不广为人知,但sedawk是。
Volker Siegel '18

@Auspex:因为dirname和basename在stdin上cat text | basename不起作用,所以将不起作用。因此,要OP的问题得到妥善解决使用dirnamebasename将涉及xargs
波德

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
尽管这个答案很
不合理

同意-不是理智,而是坏蛋!
Volker Siegel '18

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--呢?这样您就可以推崇printbla bla。
fedorqui

3

由于问题已被编辑,因此添加到egmont的答案中...

如果要使用-f1删除第一个字段,请使用--complement

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,

@muru OP是1个代表用户。不是以2k授予编辑特权吗?askubuntu.com/help/privileges/edit
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy任何人都可以建议编辑。
muru

+1-我之前没有注意到该--complement选项,并且手册页是圆形的。补语是指补语。我发现了一个漂亮的切教程覆盖它在yourownlinux.com/2015/05/...这就像-vgrep。除了匹配的东西,给我一切。

2
-f2-是的简单形式-f1 --complement
egmont
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.