84

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

/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作为字符串的第二部分,我显然做错了什么......也许有更简单的方法?

4

8 回答 8

116

如果你想删除一定数量的路径组件,你应该使用cutwith -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-
# output:
# some/deepish/dir

要保留前两个组件:

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

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

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

要保留最后三个组件:

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

或者,如果您想在特定组件之前删除所有内容,则sed可以:

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

或在特定组件之后:

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

如果您不想保留您指定的组件,那就更容易了:

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

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

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

当然,如果你匹配多个斜线,你应该切换sed分隔符:

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

请注意,这些示例都使用绝对路径,您必须尝试使它们与相对路径一起使用。

于 2015-07-30T15:59:20.957 回答
82

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

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

扩展变量时,该#..部分会去除前导匹配字符串;如果您的字符串已经在 shell 变量中,这尤其有用,例如您正在使用for循环。您也可以使用%.... 有关血腥的详细信息,请参见bash手册页。

于 2012-06-11T20:23:07.007 回答
32

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

$ s='/path/to/file/drive/file/path/'
$ echo ${s#$(dirname "$(dirname "$s")")/}
file/path/
于 2012-06-11T22:28:59.927 回答
12

使用 sed 执行此操作的一种方法是

echo /path/to/file/drive/file/path/ | sed 's:^/path/to/file/drive/::'
于 2012-06-11T20:08:50.270 回答
5

如果你想删除路径的前 N ​​部分,你当然可以使用N调用dirname,如glenn 的回答,但使用 globbing 可能更容易:

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

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

于 2014-08-14T14:52:01.417 回答
4

按照 evil otto 的建议使用${path#/path/to/file/drive/}当然是典型/最好的方法,但是由于有许多 sed 建议,因此值得指出的是,如果您使用的是固定字符串,则 sed 是矫枉过正的。你也可以这样做:

echo $PATH | cut -b 21-

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

于 2012-06-13T20:32:20.473 回答
1

纯 bash,无需对答案进行硬编码

basenames()
{
  local d="${2}"
  for ((x=0; x<"${1}"; x++)); do
    d="${d%/*}"
  done
  echo "${2#"${d}"/}"
}
  • 参数 1 - 你想保留多少个级别(原始问题中的 2 个)
  • 论点 2 - 完整路径

取自vsi_common原始版本

于 2018-04-10T16:04:28.090 回答
0

这是一个使用简单 bash 语法的解决方案,它可以容纳变量(以防您不想对完整路径进行硬编码),无需将 stdin 管道传输到sed,并包含一个for循环,以实现良好的衡量标准:

FULLPATH="/path/to/file/drive/file/path/"
SUBPATH="/path/to/file/drive/"
for i in $FULLPATH;
do
echo ${i#$SUBPATH}
done

正如@evil otto 上面提到的,#在这种情况下,该符号用于删除前缀。

于 2021-06-03T20:39:50.057 回答