Entrada de padrão de tubulação para encontrar o comando

1

Eu tenho um cenário em que estou tentando find de vários arquivos com base na saída de outro comando.

O comando em si é

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

e isso me dá a seguinte saída

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

Existe alguma maneira que eu possa alimentar esta entrada para o seguinte comando find, a fim de encontrar a localização de cada um desses arquivos?

find /usr -name <INPUT_LINE>
    
por ctor 07.03.2016 / 20:41

3 respostas

2

Supondo que não existam caracteres problemáticos (por exemplo, aqueles em IFS ) nos nomes das bibliotecas, faça um loop sobre a lista e passe cada um para um novo achado:

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

Caso contrário, para uma única passagem do sistema de arquivos (a acima faz uma para cada arquivo de entrada), a opção find -name não é adequada para corresponder a uma lista de nomes de arquivos, portanto talvez a saída de uma única pesquisa no sistema de arquivos possa ser passada para% código%. A pesquisa também pode ser reduzida procurando apenas em diretórios em grep que são denominados /usr :

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

Use um nome de arquivo lib generated se mktemp for um problema. Com um shell sofisticado, o arquivo de padrões para blah poderia ser gerado em tempo real por meio de alguma forma de substituição de processo.

    
por 07.03.2016 / 21:00
0

Você pode transformar os nomes de arquivos em uma única expressão regular e usar as opções find -regex ou -iregex (sem distinção entre maiúsculas e minúsculas).

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

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

xargs coloca todos os nomes de arquivos em uma linha, separados por espaços, e o seguinte sed altera os espaços para | e . para \. . O comando find só é executado se $ libs não estiver vazio.

Nota: se muitos (milhares) de nomes de arquivos forem gerados por ./libopt , o comando xargs produzirá 2 ou mais linhas, $ libs será muito grande para caber em uma linha de comando e isso será quebrado. Se isso é provável (parece improvável para mim, dado o que ./libopt está gerando), você poderia contornar isso executando o xargs | sed e find em um loop, por exemplo:

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

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

com zsh :

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

Veja esta resposta a uma pergunta semelhante: link para obter uma explicação e também alguma abordagem alternativa se você não tiver zsh .

    
por 07.03.2016 / 22:09

Tags