我正在寻找一个可以从 bash 脚本使用的工具,它可以为我提供给定路径的父目录列表。
foo/bar/moocow
例如,给出我想输出的输入:
foo
foo/bar
foo/bar/moocow
如果我可以输入多个路径并获得唯一的结果,那就太好了,例如:
toolimlookingfor << EOF
dir1/file1
dir1/file2
foo/bar/moocow
EOF
输出:
dir1
dir1/file1
dir1/file2
foo
foo/bar
foo/bar/moocow
dirname
与我正在寻找的很接近,但它只给出了直接父级。我正在寻找自己和所有父母的道路。
答案1
如果您同意在/tmp
文件夹中创建新目录,则可以使用 find 命令,此方法还将负责仅打印唯一的目录名称。
#!/bin/bash
if [[ $# -eq 0 ]]; then exit; fi
mkdir -p /tmp/printnames
for i
do
mkdir -p /tmp/printnames/"$i"
done
cd /tmp/printnames
find * -type d -print
rm -r /tmp/printnames
因此,您可以创建一个临时目录结构,然后使用 find 遍历它。
答案2
使用标准的 Python 脚本pathlib
模块,处理参数而不是输入:
#! /usr/bin/env python3
import sys
from collections import OrderedDict
from pathlib import Path
paths = OrderedDict() # to maintain ordering and skip duplicates
for arg in sys.argv[1:]:
path = Path(arg)
for subpath in reversed(path.parents):
# add the parents
paths[subpath.as_posix()] = subpath
# add the path itself
paths[path.as_posix()] = path
# we don't need '.' in the output
if '.' in paths:
paths.pop('.')
print('\n'.join(paths.keys()))
(可以通过循环轻松地将其修改为使用标准输入sys.stdin
。)
例子:
% ./foo.py dir1/file1 dir1/file2 foo/bar/moocow
dir1
dir1/file1
dir1/file2
foo
foo/bar
foo/bar/moocow
答案3
这段代码就可以做到。它不使用临时文件。它适用于空白,但换行符不明确(更改\n
为\0
修复)。\0
如果要在自动化流程中使用它,则应该使用它。\0
是唯一保证不在 Unix 文件名中的字符。
它只是递归地使用dirnames
.您可以通过删除/启用某些printf
s 来调整它。使其上升或下降,或不显示根节点(.
或/
)。您的示例中没有显示根节点,但我认为这是必要的。如果没有它,/a/b/c
输出与 相同a/b/c
。
#!/bin/bash
function dirnames {
local input
local parent
input="$1"
if [[ "$input" == "" ]]
then
true
elif [[ "$input" == "." || "$input" == "/" ]]
then
printf '%s\n' "$input" #print the root node
else
#printf '%s\n' "$input" #print node (descending)
parent="$(dirname "$input")"
dirnames "$parent"
printf '%s\n' "$input" #print node (ascending)
fi
}
for d in "$@"
do
dirnames "$d"
done
用法示例
%↳ ./dirnames a/b/c
.
a
a/b
a/b/c
%↳ ./dirnames /a/b/c
/
/a
/a/b
/a/b/c
%↳
为了让它像这样工作
%↳ ./dirnames a/b/c
.
a
b
c
%↳ ./dirnames /a/b/c
/
a
b
c
%↳
然后将文件另存为dirnames
然后运行sed -r -i '17 s/("[$]input")/"$(basename \1)"/' dirnames
。现在您将拥有一个仅输出每个级别的叶子的脚本。
答案4
如果尾部斜杠(或其他分隔符)适合您,就像我的情况一样,以下解决方案对我来说是最简单、最透明的解决方案:
pth='one/two/three'
sep='/'
# split string into array by separator
arr=($(echo $pth | tr $sep '\n'))
# loop over array and append
sub=''
for index in ${!arr[@]}
do
sub+="${arr[index]}$sep"
printf "$index \t ${arr[index]} \t $sub \n"
done
输出:
0 one one/
1 two one/two/
2 three one/two/three/