echo
絶対パスと相対パスを取るコマンド (ではありません!) を実行したいと考えています。
これら 2 つの引数を取得するにはどうすればよいですか?
試み:
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
Exportd
すると、インライン スクリプトで使用できるようになります。ここでも、まったくbash
必要ありません。(できればよりスリムで高速な) スクリプトでも同様に機能します。また、ファイルごとに 1 つのシェルを実行する必要もありません。次のバリアントを使用して、インライン スクリプトにさらに多くのファイルを渡すことができます。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
。
あなたのコマンドにも私のコマンドにも GNU 固有のものは何もないことに注意してくださいfind
。これは、GNU だけでなく、POSIX 準拠の実装であればどれでも動作するはずですfind
。あなたの質問で 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}
演算子は次のように機能するため、「yes」が出力されることは保証されません。文字、 ないバイト。
たとえば、UTF-8 ロケールでは、a
との値が次の場合、 yes は出力されませんb
。
a=$'St\xc3' b=$'\xa9phane'
これらを使用すると、$c
私の名前 ( Stéphane
)がその文字$a
の半分を含み、残りの半分は(2 文字と 1 バイトは有効な文字を形成しませんが、カウントされます)になります。é
$b
${#a}
3
したがって、 ではなく に$d
なります。phane
$'\xa9phane'
ただし、 の特定のケースでは、システム ロケールで一般的に使用可能な文字セットのいずれにものエンコーディングを含むd=$a/$b
以外の文字がないため、問題はありません。/
/