パイプラインモード入力検索コマンド

パイプラインモード入力検索コマンド

find他のコマンドの出力に基づいて複数のファイルを処理しようとするシナリオがあります。

コマンド自体は

./libopt -d test . 2>&1 | sed -rn 's/Cannot find library \"(.*?)\"/\1/p'

これは私に次のような結果を与えます

libopcodes-2.25-system.so
libbfd-2.25-system.so
libz.so.1
libdl.so.2
libc.so.6
libosal.so
libarchive.so.13
libcrypto.so.1.0.0
libfreetype.so.6
libpng12.so.0
libpthread.so.0
libts-1.0.so.0
libgcc_s.so.1
libssl.so.1.0.0
libm.so.6
ld-linux.so.3
libxml2.so.2
libbz2.so.1.0
liblzma.so.5
liblzo2.so.2
libattr.so.1
libacl.so.1
libnettle.so.4

とにかく、各ファイルの場所を見つけるために、この入力を次のfindコマンドに提供できますか?

find /usr -name <INPUT_LINE>

答え1

問題のある文字(たとえば、内の文字)がライブラリ名に存在しないとし、IFSリストを繰り返して、各文字を新しいクエリに渡します。

./libopt -d test . 2>&1 | sed -rn 's/Cannot find library \"(.*?)\"/\1/p' \
| while read libname; do
  find /usr -name "$libname"
done

それ以外の場合は、単一ファイルシステムの配信(上記は各入力ファイルに対して1つずつ実行)の場合、このfind -nameオプションはファイル名リストの一致には適していないため、単一のファイルシステム検索の出力がに渡される可能性がありますgrep/usr検索範囲を絞り込むというディレクトリだけを探していますlib

./libopt -d test . 2>&1 | sed -rn 's/Cannot find library \"(.*?)\"/\1/p' > blah
find /usr/lib /usr/*/lib -type f | grep -F -f blah

mktemp問題がある場合は、blah生成されたファイル名を使用してください。高度なシェルを使用すると、grepプロセス置換形式でスキーマファイルを動的に生成できます。

答え2

ファイル名を単一の正規表現に変換するか(大文字と小文字を区別しない)オプションを使用できますfind-regex-iregex

libs=$(./libopt -d test . 2>&1 | 
       sed -rn 's/Cannot find library \"(.*?)\"/\1/p' | 
       xargs -r | sed -e 's/ /|/g ; s/\./\\./g')

[ -n "$libs" ] && find /usr -regextype egrep -iregex ".*/($libs)"

xargsすべてのファイル名をスペースで区切って1行に入力します。次のコマンドはsedスペースを|and に変更します。このコマンドは、$ libsが空でない場合にのみ実行されます。.\.find

注:出力するファイル名が多すぎると(数千)、コマンドは./libopt2xargs行以上を出力し、$ libsが大きすぎて1つのコマンドラインに収まらず中断されます。これが可能であれば(出力結果を考慮するとそうではありません)、次のようにループでandを./libopt実行してxargs | sed問題を解決できます。find

libs=$(./libopt -d test . 2>&1 | sed -rn 's/Cannot find library \"(.*?)\"/\1/p')

for re in $(echo "$libs" | xargs | sed -e 's/ /|/g ; s/\./\\./g') ; do 
    find . -regextype egrep -iregex ".*/($re)"
done

答え3

そしてzsh

files=(
  ${(f)"$(./libopt -d test . 2>&1 |
          sed -rn 's/Cannot find library \"(.*?)\"/\1/p')"})
glob=('$files['{1..$#files}']')
eval "paths=(**/(${(j:|:)glob})(D.))"
ls -ld -- $paths

同様の質問に対する答えを確認してください。https://unix.stackexchange.com/a/265815説明が必要な場合やない場合は、いくつかの選択肢を確認してくださいzsh

関連情報