O arquivo de relatórios BASH não existe, mas não

0

Eu tenho uma lista de arquivos produzidos a partir do find. Devido a um mau planejamento do gerenciamento, preciso agora registrar esses arquivos, mas o comando find demorou várias horas para ser concluído, enquanto estamos varrendo vários TB de dados. Então, meu plano era percorrer a lista de arquivos com um script e executar a estatística com base nos arquivos que já encontramos. A questão é que o BASH está continuamente informando que todos os arquivos não existem, dentro do script, mas executar qualquer comando com os arquivos fora do script (apenas no terminal) funciona bem.

EX:

sh ~/temp.sh  | head -1
stat: ./2017\ Digital/redacted\ Projects-redacted-IP.idx: stat: No such file or directory

stat -x ./2017\ Digital/redacted\ Projects-redacted-IP.idx
  File: "./2017 Digital/redacted Projects-redacted-IP.idx"
  Size: 25165824     FileType: Regular File
  Mode: (0500/-r-x------)         Uid: (redacted)  Gid: (redacted)
Device: 47,12   Inode: 440520    Links: 1
Access: Wed Jul  5 17:24:48 2017
Modify: Wed Jul  5 17:24:48 2017
Change: Wed Jul  5 17:24:48 2017

i=0
IFS=$'\n'
for j in $(cat ~/files); do
    stat -x $j
done

Estes são compartilhamentos do Windows montados em / Volumes / no OSX. Independentemente de como pareço alterar as cotações (double / single / none / etc), o script informa continuamente que TODOS os arquivos não existem. Eu também tentei uma versão em python do script:

from subprocess import call
f=open( "/Users/me/files", "r" )
for l in f:
    call(["stat","-x","/Volumes/"+l])

Com o mesmo erro. A questão parece estar diretamente relacionada a espaços nos nomes de arquivos. Desde quando codificando um arquivo diferente, sem espaços, funciona muito bem. Eu estou supondo que eu preciso fazer algo com citando minhas variáveis de forma diferente? Mas eu não posso, para minha vida, descobrir qual é a maneira correta de citar essas variáveis para fazê-lo funcionar.

    
por Greg Miller 06.07.2017 / 19:24

1 resposta

3

O problema é que os caminhos listados em ~ / files incluem escapes (barras invertidas) antes de espaços (e possivelmente outros caracteres), e estes são tratados como parte do nome do arquivo. Normalmente, quando você insere um comando como este:

stat -x ./2017\ Digital/redacted\ Projects-redacted-IP.idx

o processo de análise do shell interpreta as barras invertidas como significando que os espaços são parte do argumento (em vez de separadores entre argumentos), e depois os remove antes de passar o argumento para stat . Assim, stat realmente recebe dois argumentos: -x e ./2017 Digital/redacted Projects-redacted-IP.idx .

Por outro lado, quando você lê os caminhos de arquivo a partir de um arquivo, ele nunca passa pela etapa de escape parse-and-remove, então as fugas são passadas para stat como parte do argumento, e procura por arquivos que realmente tem barras invertidas em seus nomes (e não os encontra).

As citações não ajudarão com isso. O shell analisa (e remove) fugas, citações e tais antes substituindo valores variáveis, de modo que ele nunca acabe interpretando & removendo escapa e aspas de seus valores. (Bem, a menos que você use algo como eval , mas não faça isso - isso abre caminho para muitas oportunidades para coisas novas darem errado.)

Acontece que há uma maneira fácil de fazer a análise de escape & remoção do conteúdo do arquivo. Em um comentário, eu recomendei mudar de um loop for para um loop while read e vincular BashFAQ # 1: Como eu posso ler um arquivo (fluxo de dados, variável) linha-a-linha (e / ou campo a campo)? . Se você leu isso, ele realmente recomenda usar while IFS= read -r e diz:

The -r option to read prevents backslash interpretation (usually used as a backslash newline pair, to continue over multiple lines or to escape the delimiters). Without this option, any unescaped backslashes in the input will be discarded. You should almost always use the -r option with read.

... exceto neste caso, você deseja que as barras invertidas sejam interpretadas e removidas ("descartadas"), por isso, desative o -r . Ah, e depois coloque todas as referências de variáveis entre aspas duplas para evitar que elas sejam divididas em espaços (sem aspas duplas, a divisão acontece se os espaços tiverem ou não escape):

#!/bin/bash

i=0
while IFS= read j; do
    stat -x "$j"
done <~/files
    
por 06.07.2017 / 21:30