删除Unix上的部分路径

时间:2012-06-11 20:05:12

标签: shell unix scripting sed

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

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

8 个答案:

答案 0 :(得分:62)

如果您要删除特定数量的路径组件,则应将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

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

答案 1 :(得分:43)

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

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

#..部分在扩展变量时剥离前导匹配字符串;如果您的字符串已经在shell变量中,那么这非常有用,例如,如果您使用for循环。您也可以使用%...从变量的末尾剥离匹配的字符串(例如,扩展名)。有关详细信息,请参阅bash手册页。

答案 2 :(得分:24)

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

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

答案 3 :(得分:9)

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

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

答案 4 :(得分:4)

使用邪恶otto建议的${path#/path/to/file/drive/}肯定是典型/最好的方法,但由于有很多sed建议,值得指出的是,如果你使用的是固定字符串,sed就是矫枉过正。你也可以这样做:

echo $PATH | cut -b 21-

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

答案 5 :(得分:4)

如果您要删除路径的前N个部分,您当然可以使用 N 调用dirname,如glenn's answer但是,使用globbing可能更容易:

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

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

答案 6 :(得分:0)

纯粹的bash,没有硬编码答案

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

答案 7 :(得分:0)

这是一个使用简单 bash 语法的解决方案,它可以容纳变量(以防您不想对完整路径进行硬编码),不需要将标准输入管道传输到 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 上面提到的,# 符号用于在这种情况下删除前缀。