GNU find:在 -exec 中获取绝对路径和相对路径

A T*_*A T 0 bash find string brace-expansion command-substitution

我有一个echo我想运行的命令(不是!),它采用绝对路径和相对路径。

我如何获得这两个参数?

试图:

d=/tmp/foo;
find "$d" -type f -exec bash -c 'echo d=${1:${#d}} 1="${1%/*}"' bash {} \;
Run Code Online (Sandbox Code Playgroud)

(我喜欢 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
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 5

Export 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 {} +
Run Code Online (Sandbox Code Playgroud)

这使:

      full: /tmp/foo/bar/can/haz/bzr.txt
  relative: bar/can/haz/bzr.txt
       dir: /tmp/foo/bar/can/haz
    reldir: bar/can/haz
Run Code Online (Sandbox Code Playgroud)

但是,如果您只需要相对路径,那么这样做可能会更简单:

(cd -P -- "$d" && find . -exec sh -c 'for file do...' sh {} +)
Run Code Online (Sandbox Code Playgroud)

这也会使传递给的命令参数sh更短,从而允许find将更多参数传递给sh.

请注意,您的find命令和我的命令中都没有特定于 GNU 的内容。这应该适用于任何符合 POSIX 的find实现,而不仅仅是 GNU 的实现。在你的问题中唯一的非POSIX部分显然bash${1:offset}运营商这是一个Korn shell的运营商,而不是在POSIX sh

有关允许您指定文件类型的递归文件查找,另请参阅zsh

(cd -P -- "$d" &&
  for file (**/*(ND.)) {
    dir=$file:h
    printf '%10s: %s\n' relative $file reldir $dir
  })
Run Code Online (Sandbox Code Playgroud)

上面, the.相当于find's -type f(仅限常规文件),而sD也包括像 do 一样的隐藏文件find


作为旁注,在一般情况下:

c=$a$b; d=${c:${#a}}
[ "$b" = "$d" ] && echo yes
Run Code Online (Sandbox Code Playgroud)

不保证输出“yes”,因为${#var}and${var:offset}操作符使用字符,而不是字节

例如,在 UTF-8 语言环境中,它不会使用aand 的这些值输出 yes b

a=$'St\xc3' b=$'\xa9phane'
Run Code Online (Sandbox Code Playgroud)

有了这些,$c将包含我的名字 ( Stéphane)$a包含该é字符$b的一半,另一半${#a}将是3(2 个字符和 1 个字节未形成有效字符,但仍被计算在内)。

所以$dphane,不$'\xa9phane'

在特定情况下d=$a/$b,它应该没问题,因为系统语言环境中通常可用的字符集都/不会包含包含/.