Variáveis de ambiente no filtro da divisão

0

Então, estou tentando o conteúdo de um dispositivo de bloco grande usando split da seguinte forma:

split --bytes 10M --numeric-suffixes --filter='cat | ssh root@$remote_ip "gzip >> /root/myfilecopy.gz"' /dev/myblockdev

Mas quando eu salvo o nome do arquivo remoto em uma variável de ambiente e uso essa variável em split ' filter ', não funciona:

remote_file=/root/myfilecopy.gz
split --bytes 10M --numeric-suffixes --filter='cat | ssh root@$remote_ip "gzip >> $remote_file"' /dev/myblockdev

Isso é o que eu recebo:

bash: -c: line 0: syntax error near unexpected token 'newline'
bash: -c: line 0: 'gzip >> '
split: with FILE=x00, exit 1 from command: cat | ssh [email protected] "gzip >> $remote_file"

Parece que a variável de ambiente não está expandida adequadamente dentro do comando de filtro.

Alguma pista de como corrigir isso?

Obrigado.

    
por hebbo 07.05.2018 / 07:19

1 resposta

1

Complicado?

Variáveis de lado por um momento. Este é o seu código básico:

 split --bytes 10M --numeric-suffixes --filter='cat | ssh root@$remote_ip "gzip >> /root/myfilecopy.gz"' /dev/myblockdev

Primeiro de tudo: cat é inútil aqui .

Em seguida, acho que acrescentar os resultados de gzip -s consecutivos ao mesmo arquivo ( >> ) cancela o trabalho de split . Em teoria, no final, o que você ganha é apenas gzipped /dev/myblockdev , exatamente como você fez:

ssh root@$remote_ip 'gzip > /root/myfilecopy.gz' < /dev/myblockdev

Na prática, eu pensaria em condição de corrida. Espero que split execute ssh -s em sequência no lado local; mas eu não ficaria surpreso se, em algumas circunstâncias, vários buffers ou atrasos no lado remoto fizessem com que o próximo gzip começasse a escrever antes que o anterior terminasse. Isso corromperia myfilecopy.gz . Abrir o arquivo apenas uma vez evita isso.

Se você usou $FILE (consulte man 1 split ) e gravou em vários arquivos, eu veria o ponto de usar split . Note que isso não introduziria uma condição de corrida porque cada um desses arquivos seria aberto apenas uma vez.

Conclusão: split é provavelmente inútil, cat é inútil, com certeza; o acréscimo descuidado pode corromper o arquivo resultante.

O problema que você perguntou sobre

OK, vamos supor que você tenha suas razões para usar split e >> desta maneira (seu cat ainda é inútil).

Seu shell atual sabe o valor de $remote_file , mas split e seu (s) filtro (s) são processos filhos e eles não herdarão a variável, a menos que você export antes. Variável inexistente se expande para nada, então o fragmento relevante se parece com gzip >> (newline) , daí o erro.

O mesmo se aplica a $remote_ip . Eu acho que no seu código você não usa $remote_ip , mas o endereço IP real 192.168.0.105 . De agora em diante, eu uso remote_ip como um espaço reservado (isto é, não uma variável shell) para o endereço IP real.

Para export :

remote_file="/root/myfilecopy.gz"
export remote_file
# now your split command should utilize the variable as you expected

Como alternativa, você pode fazer com que seu shell atual expanda $remote_file no momento em que você executar split . Originalmente, a string $remote_file é deixada intacta devido às aspas simples em torno dela. A sintaxe a seguir altera o tipo de aspas apenas para essa variável:

split --bytes 10M --numeric-suffixes --filter='ssh root@remote_ip "gzip >> '"$remote_file"'"' /dev/myblockdev
#                                                     close a single quote ^              ^ and open again
#                                             variable inside double quotes ^^^^^^^^^^^^^^

Dessa forma, split nunca recebe o literal $remote_file , ele obtém seu valor.

Outra questão

Se você tivesse remote_file="/root/myfile copy.gz" , o espaço no caminho dividiria em dois argumentos no lado remoto. Por essa razão, a abordagem mais robusta requer cotação adicional. Essa é a abordagem "sem exportação" acima com aspas extras (com escape de \ ):

split --bytes 10M --numeric-suffixes --filter='ssh root@remote_ip "gzip >> \"'"$remote_file"'\""' /dev/myblockdev

Vamos tira-lo passo a passo. Entre outros argumentos, split veria o seguinte como um único:

--filter=ssh root@remote_ip "gzip >> \"/root/myfile copy.gz\""

Ele executaria esse filtro em bash :

ssh root@remote_ip "gzip >> \"/root/myfile copy.gz\""

Então ssh veria isso como um de seus argumentos:

gzip >> "/root/myfile copy.gz"

Portanto, no lado remoto, o redirecionamento seria para "/root/myfile copy.gz" . Sem essas citações adicionadas, você teria:

gzip >> /root/myfile copy.gz

que é equivalente a

gzip copy.gz >> /root/myfile

Notas adicionais

  • Se a CPU local for rápida o suficiente, considere gzip antes de ssh . Dessa forma, você envia menos dados pelos links da rede; especialmente se você preparou seu dispositivo de bloco para compactar bem .
  • Se sua intenção era executar vários processos de gzip para obter vantagem de vários núcleos de CPU, observe que eles provavelmente seriam executados em sequência; se não, uma condição de corrida - você não quer isso. Familiarize-se com pigz .
por 07.05.2018 / 10:21