
Ao trabalhar com a saída de comandos como locate
os 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 locate
ou find
e passar sua entrada como parâmetros para outro programa, você pode aproveitar a NUL
saída e a entrada delimitadas que algumas ferramentas fornecem. locate
e find
ambos têm uma opção ( locate
's -0
e find
's -print0
) que permitirá que você tenha uma saída mais amigável à programação, xargs
projetada para ser lida comisso é -0
argumento:
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 $IFS
parâ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 locate
simplesmente não é pós-processável.
A maioria locate
das implementações tem a -0
opção de gerar os caminhos dos arquivos NUL
delimitados. 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 bash
4.4+, isso poderia ser:
readarray -td '' files < <(locate -0 '*.doc')
du -hc -- "${files[@]}"
Isso ainda deixa dois problemas:
- Se
locate
nã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. - Se por outro lado
locate
encontrar muitos arquivos, você pode acabar atingindo um limite deexecve()
chamada do sistema e obter umlista de argumentos muito longaerro.
Ambos os problemas podem ser evitados fazendo:
locate -0 '*.doc' | xargs -r0 du -hc --
( -r
e -0
sendo extensões não padrão da implementação GNU de xargs
like -h
é uma extensão não padrão da implementação GNU de du
).
No entanto, isso introduz um novo problema: xargs
será executado du
várias vezes para contornar o execve()
limite, mas isso significa que você obterá várias total
linhas 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
, du
não será executado se locate
não encontrar nenhum arquivo, mas isso também significa que você não receberá uma 0 total
linha.
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ê du
pode começar a trabalhar nela assim que locate
começar a exibi-la.