Ich möchte einen Befehl (nicht echo
!) ausführen, der einen absoluten und einen relativen Pfad annimmt.
Wie komme ich zu diesen beiden Argumenten?
Versuchen:
d=/tmp/foo;
find "$d" -type f -exec bash -c 'echo d=${1:${#d}} 1="${1%/*}"' bash {} \;
(Ich mag GNU Find, weil es rekursiv ist, nach Dateien einschränken und nach Dateinamen filtern kann und nicht zu viele Shells erzeugt.)
Erwartung:
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
Antwort1
Export d
, dann ist es in Ihrem bash
Inline-Skript verfügbar. Sie brauchen es hier auch gar nicht bash
. Ihr (hoffentlich schlankeres/schnelleres) würde es auch tun. Außerdem müssen Sie nicht eine Shell pro Datei ausführen. Sie können Ihrem Inline-Skript mit der Variante sh
mehr Dateien übergeben :-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 {} +
Das ergibt:
full: /tmp/foo/bar/can/haz/bzr.txt
relative: bar/can/haz/bzr.txt
dir: /tmp/foo/bar/can/haz
reldir: bar/can/haz
Wenn Sie jedoch nur den relativen Pfad benötigen, ist es möglicherweise einfacher, Folgendes zu tun:
(cd -P -- "$d" && find . -exec sh -c 'for file do...' sh {} +)
Dadurch würden auch die an übergebenen Befehlsargumente sh
kürzer und es könnten find
mehr Argumente an übergeben werden sh
.
Beachten Sie, dass weder Ihr noch mein Befehl GNU-spezifisch sind find
. Das sollte in jeder POSIX-kompatiblen find
Implementierung funktionieren, nicht nur in der GNU-Implementierung. Der einzige nicht-POSIX-Teil in Ihrer Frage war offensichtlich bash
und der ${1:offset}
Operator, der ein Korn-Shell-Operator ist, nicht in POSIX sh
.
Informationen zu einer rekursiven Dateisuche, bei der Sie den Dateityp angeben können, finden Sie auch unter zsh
:
(cd -P -- "$d" &&
for file (**/*(ND.)) {
dir=$file:h
printf '%10s: %s\n' relative $file reldir $dir
})
Oben .
ist das das Äquivalent von find
( -type f
nur normale Dateien), während D
wie find
„dos“ auch versteckte Dateien einschließt.
Als Randbemerkung, im allgemeinen Fall:
c=$a$b; d=${c:${#a}}
[ "$b" = "$d" ] && echo yes
Es ist nicht garantiert, dass "ja" ausgegeben wird, da die Operatoren ${#var}
und ${var:offset}
mitFiguren, nichtBytes.
Beispielsweise würde in einem UTF-8-Gebietsschema mit diesen Werten von a
und nicht „yes“ ausgegeben b
:
a=$'St\xc3' b=$'\xa9phane'
Damit $c
würde mein Vorname ( Stéphane
) $a
die Hälfte dieses é
Zeichens enthalten und $b
die andere Hälfte ${#a}
wäre 3
(2 Zeichen und 1 Byte, die kein gültiges Zeichen bilden, aber trotzdem gezählt werden).
So $d
wäre es phane
, nicht $'\xa9phane'
.
Im speziellen Fall von d=$a/$b
sollte es jedoch in Ordnung sein, da keiner der in Systemgebietsschemas allgemein verfügbaren Zeichensätze ein anderes Zeichen als /
das hätte, das die Kodierung von enthält /
.