У меня есть команда (не echo
!), которую я хочу выполнить, и которая принимает абсолютный и относительный пути.
Как мне получить эти два аргумента?
Пытаться:
d=/tmp/foo;
find "$d" -type f -exec bash -c 'echo d=${1:${#d}} 1="${1%/*}"' bash {} \;
(Мне нравится GNU find, потому что он рекурсивен, может ограничивать по файлу, может фильтровать по имени файла и не порождает лишних оболочек)
Ожидание:
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
Export d
, тогда он будет доступен в вашем встроенном скрипте. Вам также здесь совсем bash
не нужно . Ваш (надеюсь, более тонкий/быстрый) тоже подойдет. Кроме того, вам не нужно запускать одну оболочку для каждого файла. Вы можете передать больше файлов в ваш встроенный скрипт с помощью варианта:bash
sh
-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
.
find
Обратите внимание, что в вашей команде нет ничего специфичного для GNU, как и в моей. Это должно работать в любой POSIX-совместимой find
реализации, не только в GNU. Единственная не-POSIX часть в вашем вопросе, очевидно, bash
и ${1:offset}
оператор, который является оператором оболочки Korn, а не в POSIX sh
.
Для рекурсивного поиска файлов, который позволяет указать тип файла, см. также zsh
:
(cd -P -- "$d" &&
for file (**/*(ND.)) {
dir=$file:h
printf '%10s: %s\n' relative $file reldir $dir
})
Вышеуказанный эквивалент .
соответствует (только обычные файлы), а также включает скрытые файлы, как и .find
-type f
D
find
В качестве примечания: в общем случае:
c=$a$b; d=${c:${#a}}
[ "$b" = "$d" ] && echo yes
Не гарантируется вывод «да», поскольку ${#var}
и${var:offset}
работают сперсонажи, нетбайты.
Например, в локали UTF-8 он не выведет yes со следующими значениями a
и b
:
a=$'St\xc3' b=$'\xa9phane'
С ними, $c
будет содержать мое имя ( Stéphane
) $a
содержит половину этого é
символа, а $b
другая половина ${#a}
будет 3
(2 символа и 1 байт, не образующие допустимый символ, но все равно учитываемые).
Так $d
бы и было phane
, нет $'\xa9phane'
.
Однако в конкретном случае d=$a/$b
это должно быть нормально, поскольку ни один из наборов символов, обычно доступных в системных локалях, не будет содержать символ, отличный от /
содержащего кодировку /
.