echo
我有一个我想运行的命令(不是!),它采用绝对路径和相对路径。
我如何得到这两个参数?
试图:
d=/tmp/foo;
find "$d" -type f -exec bash -c 'echo d=${1:${#d}} 1="${1%/*}"' bash {} \;
(我喜欢 GNU find,因为它是递归的,可以按文件限制,可以按文件名过滤,并且不会生成过多的 shell)
期待:
mkdir -p /tmp/foo/bar/can/haz; touch /tmp/foo/bar/can/haz/bzr.txt
# cmd is run, output is:
d=bar/can/haz 1=/tmp/foo/bar/can/haz
答案1
导出d
,然后它将在您的内联脚本中可用bash
。你也bash
根本不需要这里。你的(希望更苗条/更快)sh
也会这样做。此外,您不需要为每个文件运行一个 shell。您可以使用以下变体将更多文件传递给内联脚本-exec cmd {} +
:
d=/tmp/foo
export d
find "$d" -type f -exec sh -c '
for file do
relative=${file#"$d/"}
dir=${file%/*}
relative_dir=${relative%/*}
relative_dir=${relative_dir:-.}
printf "%10s: %s\n" full "$file" \
relative "$relative" \
dir "$dir" \
reldir "$relative_dir"
done' sh {} +
这使:
full: /tmp/foo/bar/can/haz/bzr.txt
relative: bar/can/haz/bzr.txt
dir: /tmp/foo/bar/can/haz
reldir: bar/can/haz
但如果您只需要相对路径,那么执行以下操作可能会更简单:
(cd -P -- "$d" && find . -exec sh -c 'for file do...' sh {} +)
这也将使传递的命令参数sh
更短,因此允许find
传递更多参数sh
。
请注意,你的命令和我的命令中都没有任何特定于 GNU 的内容find
。这应该适用于任何符合 POSIX 标准的find
实现,而不仅仅是 GNU 实现。您问题中唯一的非 POSIX 部分显然是Korn shell 运算符,而不是 POSIX 中的运算bash
符。${1:offset}
sh
对于允许您指定文件类型的递归文件查找,另请参阅zsh
:
(cd -P -- "$d" &&
for file (**/*(ND.)) {
dir=$file:h
printf '%10s: %s\n' relative $file reldir $dir
})
上面,.
相当于find
's -type f
(仅限常规文件),而D
也像find
does 一样包含隐藏文件。
作为旁注,在一般情况下:
c=$a$b; d=${c:${#a}}
[ "$b" = "$d" ] && echo yes
不保证输出“yes”,因为${#var}
and${var:offset}
运算符与人物, 不是字节。
a
例如,在 UTF-8 语言环境中,对于和 的这些值,它不会输出 yes b
:
a=$'St\xc3' b=$'\xa9phane'
有了这些,$c
将包含我的名字 ( Stéphane
)包含该字符$a
的一半,另一半将是(2 个字符和 1 个字节不形成有效字符,但仍然计数)。é
$b
${#a}
3
如此$d
会phane
,不$'\xa9phane'
。
但在特定情况下d=$a/$b
,应该没问题,因为系统区域设置中通常可用的字符集都不会包含/
包含 编码的字符以外的字符/
。