Como redirecionar uma lista de caminhos legíveis por humanos para outro comando?

Como redirecionar uma lista de caminhos legíveis por humanos para outro comando?

Ao trabalhar com a saída de comandos como locateos que produzem listas de caminhos em "forma legível por humanos" (ou seja, sem \espaços na frente), como você redireciona sua saída para outro comando?

A saída de $ locate [something]produz caminhos com espaços, o que inibe outros programas de utilizar os caminhos caso contenham espaços. Por exemplo, se eu fosse

$ du -h `locate *.doc`

isso produzirá um erro em todos os arquivos e diretórios que contêm espaços. (envolver as marcas em espaços não funciona)

Responder1

Qual é o motivo específico pelo qual você está usando locate? Isso parece fazer o que você pediu:

find . -type f -name '*doc' -exec du -h "{}" \;

Dito isto, se vocêrealmenteSe quiser usar uma ferramenta como locateou finde passar sua entrada como parâmetros para outro programa, você pode aproveitar a NULsaída e a entrada delimitadas que algumas ferramentas fornecem. locatee findambos têm uma opção ( locate's -0e find's -print0) que permitirá que você tenha uma saída mais amigável à programação, xargsprojetada para ser lida comisso é -0argumento:

find . -type f -name '*doc' -print0 | xargs -0 du -h

locate -0 '*doc' | xargs -0 du -h

Responder2

Se você quiser/precisar passar a mesma linha para vários comandos, algo assim funcionaria:

#!/usr/bin/env bash

T="${IFS}" # Save off the Internal Field Separator

IFS=$'\n' # Set it to newline.

while read file_line
do
        echo "--"
        echo "${file_line}"
        echo "--"
done <<< $(locate $1) 
IFS="${T}  # Set it back to the original IFS. 

É uma boa ideia embrulharqualquervariáveis ​​que podem conter espaços em "".

Responder3

Deixar as substituições de comando ( $(...)ou a `...`forma arcaica) sem aspas invoca split+glob (dividir apenas em zsh) em shells do tipo Bourne.

A divisão é feita em caracteres do $IFSparâmetro especial que contém espaço, tabulação e nova linha (e NUL em zsh) por padrão, o que explica por que seu comando não funciona para nomes de arquivos que contêm caracteres de espaço.

Você poderia fazer:

(IFS='
' # split on newline only
set -o noglob # disable glob
du -hc -- $(locate '*.doc'))

Mas isso ainda falharia se houvesse nomes de arquivos que contivessem caracteres de nova linha. A saída de locatesimplesmente não é pós-processável.

A maioria locatedas implementações tem a -0opção de gerar os caminhos dos arquivos NULdelimitados. Sendo NUL o único valor de byte que não pode ocorrer em um caminho de arquivo, isso significa que a saída é pós-processável. Você só precisa dividir em NULs.

Em zsh:

IFS=$'\0'
du -hc -- $(locate -0 '*.doc')

Ou, melhor, usando um operador split-on-NUL explícito:

du -hc -- ${(0)"$(locate -0 '*.doc')"}

Em bash4.4+, isso poderia ser:

readarray -td '' files < <(locate -0 '*.doc')
du -hc -- "${files[@]}"

Isso ainda deixa dois problemas:

  1. Se locatenão encontrar nenhum arquivo, du -hc --será executado sem argumentos, o que significa que fornecerá o uso do disco do diretório de trabalho atual.
  2. Se por outro lado locateencontrar muitos arquivos, você pode acabar atingindo um limite de execve()chamada do sistema e obter umlista de argumentos muito longaerro.

Ambos os problemas podem ser evitados fazendo:

locate -0 '*.doc' | xargs -r0 du -hc --

( -re -0sendo extensões não padrão da implementação GNU de xargslike -hé uma extensão não padrão da implementação GNU de du).

No entanto, isso introduz um novo problema: xargsserá executado duvárias vezes para contornar o execve()limite, mas isso significa que você obterá várias totallinhas e também o uso do disco para um arquivo vinculado várias vezes pode acabar sendo contado várias vezes.

Graças a -r, dunão será executado se locatenão encontrar nenhum arquivo, mas isso também significa que você não receberá uma 0 totallinha.

Com versões recentes do GNU du, esses problemas podem ser resolvidos com:

locate -0 '*.doc' | du --files0-from=- -hc

Desta vez, a lista de arquivos é passada por meio de um canal em vez de argumentos, portanto não há limite de tamanho dos argumentos. Isso também significa que não há necessidade de alocar grandes quantidades de memória para armazenar essa lista e que você dupode começar a trabalhar nela assim que locatecomeçar a exibi-la.

informação relacionada