在Unix上删除部分路径


70

我正在尝试删除字符串中的部分路径。我有路径:

/path/to/file/drive/file/path/

我想删除第一部分/path/to/file/drive并产生输出:

file/path/

注意:我在while循环中有几个路径,/path/to/file/drive所有路径都相同,但是我只是在寻找删除所需字符串的“方法”。

我找到了一些示例,但无法使它们起作用:

echo /path/to/file/drive/file/path/ | sed 's:/path/to/file/drive:\2:'
echo /path/to/file/drive/file/path/ | sed 's:/path/to/file/drive:2'

\2 作为字符串的第二部分,我显然做错了什么……也许有更简单的方法吗?

Answers:


70

您也可以使用POSIX shell变量扩展来执行此操作。

path=/path/to/file/drive/file/path/
echo ${path#/path/to/file/drive/}

#..扩展变量时,该部分会剥离开头的匹配字符串。如果您的字符串已经在shell变量中,例如在使用for循环时,这将特别有用。您也可以使用,从变量的末尾剥离匹配的字符串(例如,扩展名)%...。有关bash详细信息,请参见手册页。


谢谢...是的,我正在使用shell变量执行此操作。这两部分都是变量,我需要删除的部分和完整路径。
esausilva 2012年

优秀的!但是,当字符串“来自管道”时如何使用呢?
birgersp

@Birger如果字符串来自管道,则需要将其放入变量以使用Shell变量扩展。或者只是sed在这种情况下使用。
邪恶otto


95

如果您想删除一定数量的路径组件,则应cut与结合使用-d'/'。例如,如果path=/home/dude/some/deepish/dir

删除前两个组件:

# (Add 2 to the number of components to remove to get the value to pass to -f)
$ echo $path | cut -d'/' -f4-
some/deepish/dir

要保留前两个组件:

$ echo $path | cut -d'/' -f-3
/home/dude

要删除最后两个组件(rev将字符串反转):

$ echo $path | rev | cut -d'/' -f4- | rev
/home/dude/some

要保留最后三个组件:

$ echo $path | rev | cut -d'/' -f-3 | rev
some/deepish/dir

或者,如果您要删除某个特定组件之前的所有内容,则sed可以:

$ echo $path | sed 's/.*\(some\)/\1/g'
some/deepish/dir

或在特定组件之后:

$ echo $path | sed 's/\(dude\).*/\1/g'
/home/dude

如果您不想保留要指定的组件,则更加容易:

$ echo $path | sed 's/some.*//g'
/home/dude/

如果您想保持一致,也可以匹配斜杠:

$ echo $path | sed 's/\/some.*//g'
/home/dude

当然,如果要匹配多个斜杠,则应切换sed定界符:

$ echo $path | sed 's!/some.*!!g'
/home/dude

请注意,这些示例都使用绝对路径,因此您必须四处使用才能使它们与相对路径一起使用。


惊人的答案,特别是双重rev技巧。明天我的投票结束时将投票。
西罗Santilli郝海东冠状病六四事件法轮功

1
@CiroSantilli巴拿马文件六四事件法轮功:)很高兴它有所帮助
ACK_stoverflow '16

1
以原始的Unix精神来说,它是一个极好的信息丰富的答案,比{chopsquiggleSquiggle}好得多:only:shellversionyoumaynothave。
narration_sd

谢谢你的例子!但是,“ cut -d'/'-f-3”不是“保留前两个成分(假设前导斜线)”而不是“删除后三个成分”吗?我知道这对于确切的例子没有什么影响,但是会更加慷慨。
jojoob

要删除最后三个组件(无论路径有多少个组件):echo $ path | 转速| 切-d'/'-f4- | rev
jojoob

28

如果您不想对要删除的零件进行硬编码:

$ s='/path/to/file/drive/file/path/'
$ echo ${s#$(dirname "$(dirname "$s")")/}
file/path/

2
我花了2个小时来寻找方法。并且您是唯一发布一种无需硬编码即可显示目录名称的方法的人。我需要做:'查找/ path / to / file / drive / file / * _ TST -maxdepth 0 -type d'但是我只想显示不带完整路径的目录名称。做到了。
Whitecat

@Whitecat就是您想要的,请阅读“ man find”,特别是“ -printf”。您可以指定'-printf“%h \ n”'。只要记住,它将为每个匹配的文件打印目录,因此您希望通过“ uniq”进行过滤。
阿莫斯·夏皮拉

12

用sed做到这一点的一种方法是

echo /path/to/file/drive/file/path/ | sed 's:^/path/to/file/drive/::'

1
太棒了–我不知道sed分隔符可以是“:”(冒号),而不是“ /”(斜杠)。优雅且完美。
stachyra

2
只要您保持一致,几乎可以对sed使用任何定界符,而不仅仅是/和:。
囚犯

@ Prisoner13每天都有新东西!
coffman21'9

5

如果要删除路径的前N个部分,当然可以使用N个对的调用dirname,如glenn的答案所示,但使用globbing可能更容易:

path=/path/to/file/drive/file/path/
echo "${path#*/*/*/*/*/}"   #  file/path/

具体来说,${path#*/*/*/*/*/}是指“返回值$path减去包含5个斜杠的最短前缀”


4

${path#/path/to/file/drive/}按邪恶的奥托的建议使用它当然是这样做的典型/最佳方法,但是由于有许多sed建议,因此值得指出的是,如果您使用固定的琴弦,则sed是过大的。您也可以这样做:

echo $PATH | cut -b 21-

丢弃前20个字符。同样,您可以${PATH:20}在bash或$PATH[20,-1]zsh中使用。


谢谢。我使用的是邪恶奥托的答案。我要删除的部分是固定的,但是如果我将脚本移动到其他框/不同路径,则可以更改。因此,拥有要从变量中的路径中删除的部分使其比计数更容易.....但是您提供的信息很容易了解:)
esausilva 2012年

1

纯bash,无需硬编码答案

basenames()
{
  local d="${2}"
  for ((x=0; x<"${1}"; x++)); do
    d="${d%/*}"
  done
  echo "${2#"${d}"/}"
}
  • 参数1-您要保留几级(原始问题中为2)
  • 论点2-完整路径

取自vsi_common原始版本


1
天哪,此页上的最佳答案!我需要使用最便携的结构的一般情况。你钉了!谢谢!
詹姆斯·麦迪逊
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.