Eu tenho um script que pesquisa todos os arquivos em várias subpastas e arquivos para tar. Meu script é
for FILE in `find . -type f -name '*.*'`
do
if [[ ! -f archive.tar ]]; then
tar -cpf archive.tar $FILE
else
tar -upf archive.tar $FILE
fi
done
O comando find me fornece a seguinte saída
find . -type f -iname '*.*'
./F1/F1-2013-03-19 160413.csv
./F1/F1-2013-03-19 164411.csv
./F1-FAILED/F2/F1-2013-03-19 154412.csv
./F1-FAILED/F3/F1-2011-10-02 212910.csv
./F1-ARCHIVE/F1-2012-06-30 004408.csv
./F1-ARCHIVE/F1-2012-05-08 190408.csv
Mas a variável FILE armazena apenas a primeira parte do caminho ./F1/F1-2013-03-19 e, em seguida, a próxima parte 160413.csv .
Eu tentei usar read
com um loop while,
while read `find . -type f -iname '*.*'`; do ls $REPLY; done
mas eu recebo o seguinte erro
bash: read: `./F1/F1-2013-03-19': not a valid identifier
Alguém pode sugerir uma maneira alternativa?
Atualizar
Conforme sugerido nas respostas abaixo, atualizei os scripts
#!/bin/bash
INPUT_DIR=/usr/local/F1
cd $INPUT_DIR
for FILE in "$(find . -type f -iname '*.*')"
do
archive=archive.tar
if [ -f $archive ]; then
tar uvf $archive "$FILE"
else
tar -cvf $archive "$FILE"
fi
done
A saída que eu recebo é
./test.sh
tar: ./F1/F1-2013-03-19 160413.csv\n./F1/F1-2013-03-19 164411.csv\n./F1/F1-2013-03-19 153413.csv\n./F1/F1-2013-03-19 154412.csv\n./F1/F1-2012-09-10 113409.csv\n./F1/F1-2013-03-19 152411.csv\n./.tar\n./F1-FAILED/F3/F1-2013-03-19 154412.csv\n./F1-FAILED/F3/F1-2013-03-19 170411.csv\n./F1-FAILED/F3/F1-2012-09-10 113409.csv\n./F1-FAILED/F2/F1-2011-10-03 113911.csv\n./F1-FAILED/F2/F1-2011-10-02 165908.csv\n./F1-FAILED/F2/F1-2011-10-02 212910.csv\n./F1-ARCHIVE/F1-2012-06-30 004408.csv\n./F1-ARCHIVE/F1-2011-08-17 133905.csv\n./F1-ARCHIVE/F1-2012-10-21 154410.csv\n./F1-ARCHIVE/F1-2012-05-08 190408.csv: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors
IFS=$'\n'
antes do `loop for para torná-la analisar por cada linhaRespostas:
Usar
for
comfind
a abordagem errada aqui, veja, por exemplo, este artigo sobre a lata de worms que você está abrindo.A abordagem recomendada é usar
find
,while
eread
como descrito aqui . Abaixo está um exemplo que deve funcionar para você:Dessa forma, você delimita os nomes de arquivos com
\0
caracteres nulos ( ), isso significa que variações no espaço e outros caracteres especiais não causarão problemas.Para atualizar um arquivo morto com os arquivos
find
localizados, você pode transmitir sua saída diretamente paratar
:Observe que você não precisa diferenciar entre se o arquivo existe ou não,
tar
o manipulará com sensatez. Observe também o uso-printf
aqui para evitar a inclusão do./
bit no arquivo morto.fonte
./
as tar../.tar tar: ./archive.tar: file is the archive; not dumped
if [[ "$FILE" == "./" ]]; then
continue
./
pouco com a-printf
resposta atualizada. No entanto, não deve fazer diferença se estiver incluído ou não, pois apenas faz referência ao diretório atual. Também incluí umafind/tar
combinação alternativa que você pode querer usar.sort
os resultados antes de iterá-los, será necessáriosort -z
o separador nulo.Tente citar o
for
loop assim:Sem aspas, o bash não lida bem com espaços e novas linhas (
\n
) ...Tente também configurar
fonte
comm
para comparar listagens de arquivos classificados e os nomes de arquivos tinham espaços, apesar de citar variáveis que não estavam funcionando. Então vi cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html e a solução de definir $ IFS com IFS = $ (echo -en "\ n \ b") funcionou para mim.Isso funciona e é mais simples:
Agradecemos a Rupa ( https://github.com/rupa/z ) por esta resposta.
fonte
Além da citação adequada, você pode dizer
find
para usar um separador NULL e, em seguida, ler e processar os resultados em umwhile
loopIsso deve lidar com todos os nomes de arquivos compatíveis com POSIX - consulte
man find
fonte
fonte
Fiz algo assim para encontrar arquivos que podem conter espaços.
Trabalhou como um encanto :)
fonte
A maioria das respostas aqui são interrompidas se houver um caractere de nova linha no nome do arquivo. Eu uso o bash mais de 15 anos, mas apenas interativo.
Em Python, você pode usar os.walk (): http://docs.python.org/2/library/os.html#os.walk
E o módulo tarfile: http://docs.python.org/2/library/tarfile.html#tar-examples
fonte
Eu acho que você pode estar melhor usando
find
a opção -exec.O Find executa o comando usando uma chamada do sistema, para que os espaços e as novas linhas sejam preservados (em vez de um canal, o que exigiria a citação de caracteres especiais). Observe que "tar -c" funciona se o arquivo já existe ou não, e que (pelo menos com o bash) nem {} nem + precisam ser citados.
fonte
Como o minerz029 sugeriu, é necessário citar a expansão do
find
comando. Você também precisa citar todas as substituições de$FILE
no seu loop.Observe que a
$()
sintaxe deve ser preferida ao uso de backticks; veja esta pergunta de U&L . Também removi a[[
palavra - chave e a substitui pelo[
comando porque é POSIX.fonte
[[
e[
, parece que[[
é mais recente e suporta mais recursos, como globbing e correspondência de expressões regulares.[[
é apenas embash
, no entanto, nãosh
[[
apoios globbing. De acordo com o wiki de Greg , nenhum globbing ocorre dentro[[
.[ "ab" == a? ] && echo "true"
então[[ "ab" == a? ]] && echo "true"
a*
significa "a seguido por qualquer número de caracteres" em vez de "todos os arquivos cujos nomes começam coma
e têm qualquer número de caracteres posteriormente". Tente[ ab = a* ] && echo true
vs.[[ ab == a* ]] && echo true
.[[
ainda faz expressões regulares, enquanto[
não. Deve ter ficado confuso