私は私ではないものを探しています$PATH
。
現在私はこれをしています
find / \( -path "/opt" -prune -o -path "/var" -prune -o -path "/bin" -prune -o -path "/sbin" -prune -o -path "/usr" -prune -o -path "/opt" \) -o -type f -executable -exec file {} \;
IFS=:
より良い方法があると思います。 forループを使用して複数の部分を分離しようとしましたが、PATH
正しく機能しませんでした。
編集:これにスクリプトを使用したくないと指定する必要があります。
答え1
GNUfind
とbash
(質問で使用されている)シェルを想定すると、以下は望ましいタスクを実行する短いスクリプトです。
#!/bin/bash
IFS=:
set -f
args=( -false )
for dirpath in $PATH; do
args+=( -o -path "$dirpath" )
done
find / \( \( "${args[@]}" \) -o \
\( -type d \( ! -executable -o ! -readable \) \) \) -prune -o \
-type f -executable -exec file {} +
args
まず、動的に設定されたパラメータを含む配列を作成しますfind
。コロンで値(変数に割り当てた値)を分割して$PATH
これを行いますIFS
。$PATH
ループヘッダに引用されていないコンテンツを使用すると、分割が発生します。
通常、シェルは分割によって生成された単語ごとにファイル名globbingを呼び出します$PATH
が、set -f
ディレクトリパスにワイルドカード文字が含まれている場合に備えてファイル名globbingを使用しました(オペランドはこれをパターンとして解釈している$PATH
ため、まだ問題があります。 )。-path
find
私のPATH
変数に文字列が含まれている場合
/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin
これにより、args
次のリストが表示されます(ここの各行は配列の別の要素であり、実際には中間に改行文字を含む文字列のセットではありません)。
-false
-o
-path
/usr/bin
-o
-path
/bin
-o
-path
/usr/sbin
-o
-path
/sbin
-o
-path
/usr/X11R6/bin
-o
-path
/usr/local/bin
-o
-path
/usr/local/sbin
リストはfind
括弧で囲まれ、コマンド呼び出しに挿入されます。-prune
上記のように一度だけ使用すればよいので、各ディレクトリに対して繰り返す必要はありません。
実行不可能または読めないディレクトリを削除することにしました。これにより、コンテンツにアクセスしたりリストしたりできないディレクトリに対する多くの権限エラーが排除されます。find
このビットを削除してコマンドを単純化するには、次のようにします。
find / \( "${args[@]}" \) -prune -o \
-type f -executable -exec file {} +
また、file
各パス名を一度実行するのではなく、見つかったパス名を一括して実行します。
答え2
これにより、zsh
次のことができます。
set -o extendedglob
LC_ALL=C find / -regextype egrep \
-regex ${(j[|])${(u)path:P}//(#m)[][.\$^*()+{}\\|.]/\\$MATCH} -prune -o \
-type f -executable -exec file {} +
$path
特別な配置です束$PATH
環境変数に。$path:P
各メンバーの実際のパスを取得します(絶対、標準、シンボリックリンクされていません)。${(u)array}
重複排除(正規化後)${array//(#m)pattern/\\$MATCH}
\
一致するものの前にを追加しますpattern
(ここにはすべてのegrep正規表現演算子があります)。${(j[|])array}
配列の要素を連結して正規表現を|
取得します。/dir|/dir\.2|...