Usando xargs para copiar texto em uma matriz de arquivos

0

Estou tentando copiar a saída de um arquivo em vários arquivos usando echo, xargs e cp. Meu problema é que o xargs só está imprimindo no primeiro arquivo da minha matriz, em vez de imprimir uma cópia em todos os 3 arquivos. Estou usando o xargs incorretamente ou minha sintaxe está incorreta? Eu tenho trabalhado nisso por alguns dias e várias páginas do Google sem sorte até agora. Qualquer ajuda é muito apreciada!

#!/bin/bash

NF1=/home/user3/mynewfile
U3=/home/user3/
File=(grades mynewfile mynewfile1 mynewfile2)

mkdir -p /home/user3/{CIT/{tests/,grades/},MyStuff/{Tests/,Labs/},NOS/};
echo /etc/hosts.allow > $NF1;
echo $U3/CIT/tests/${File[*]} $U3/CIT/grades/${File[2]} | xargs -n 1 cp $NF1
    
por LinuxCare 02.10.2015 / 02:00

2 respostas

1

Como você suspeitava, ele tinha algo a ver com a sintaxe, mas eu também encontrei alguns outros problemas, e surgiu uma versão que simplesmente descartou o uso de xargs em favor de um for loop:

#!/bin/bash

U3=/home/user3/
NF1=/home/user3/mynewfile
File=(grades mynewfile mynewfile1 mynewfile2)

mkdir -p /home/user3/{CIT/{tests,grades},MyStuff/{Tests,Labs},NOS};

echo /etc/hosts.allow > $NF1;

for i in "${File[@]}"; do
    cp $NF1 $U3/$i
done

cp $NF1 $U3/CIT/grades/${File[2]}
  • mkdir linha foi simplificada para descartar as barras finais desnecessárias, mkdir ainda cria diretórios com barra final ou não, portanto não há necessidade de mais digitação

As razões para o restante das alterações:

Barra redundante

Em primeiro lugar, ao testar algumas linhas do código original:

$ U3=/home/user3/
$ File=(grades mynewfile mynewfile1 mynewfile2)
$ echo $U3/CIT/grades/${File[2]}
/home/user3//CIT/grades/mynewfile1

O caminho salvo em $U3 foi definido com uma barra final, então a linha $U3/CIT/grades/${File[2]} também possui uma barra após $U3 , fazendo com que o bash a expanda para /home/user3//CIT/grades/mynewfile1 , isso é um problema porque% de barra dupla// não é o mesmo que / , cp por exemplo pode reclamar no such file or directory .

Portanto, se você quis dizer uma barra simples / , o método recomendado é definir apenas $U3 para não ter nenhuma barra final:

$ U3=/home/user3
$ File=(grades mynewfile mynewfile1 mynewfile2)
$ echo $U3/CIT/tests/${File[2]}
/home/user3/CIT/tests/mynewfile1

Portanto, isso agora resulta em um caminho adequado, sem barras redundantes.

Expansão de chave incorreta

Com isso corrigido, o próximo bug foi:

$ echo $U3/CIT/tests/${File[*]}
/home/user3/CIT/tests/grades mynewfile mynewfile1 mynewfile2

Suponho que você pretendia expandir os nomes dos arquivos na matriz File , usando /home/user3/CIT/tests como um prefixo comum, como essa expansão de chave com vírgulas:

$ echo tweedle{dum,dee}
tweedledum tweedledee

Nesta forma de expansão de chave

  • uma string fica bem ao lado da chave { antes ou depois de } ou de ambos, o que você fez corretamente
  • mas uma word , comma , outra palavra é usada, etc
  • no entanto, você coloca um ${File[*]} , eu ainda não vi funcionar com o conteúdo da matriz dessa maneira

Em vez disso, para produzir uma lista feita combinando a mesma palavra ou string inicial comum ( $U3 ) mais outra parte que seja diferente baseada em uma matriz ( $File ), eu recomendo um for loop:

$ for i in "${File[@]}"; do
> echo $U3/$i
> done

Observe que você não digita > , bash automaticamente fornece isso para indicar continuação de linha. Em um script você acabou de ter:

for i in "${File[@]}"; do
    echo $U3/$i
done

O resultado é sempre

/home/user3/grades
/home/user3/mynewfile
/home/user3/mynewfile1
/home/user3/mynewfile2
  • em for i in "${File[@]}"; do , a cotação ( " ), mais @ é importante para ter o loop for entendendo corretamente cada nome de arquivo em $File array como argumentos separados.

Teste

Por fim, o objetivo é copiar um único arquivo, referenciado pela variável $NF1 , para vários locais, definidos pela expansão de $U3 plus $File array mais $U3/CIT/tests/${File[2]}

A melhor prática para fazer um teste com echo e o comando que você pretende executar, neste caso cp , para que você possa ver o que será executado, a menos que queira usar set . Então, primeiro para o nosso teste:

$ NF1=/home/user3/mynewfile

Então

$ for i in "${File[@]}"; do
> echo cp $NF1 $U3/$i
> done
cp /home/user3/mynewfile /home/user3/grades
cp /home/user3/mynewfile /home/user3/mynewfile
cp /home/user3/mynewfile /home/user3/mynewfile1
cp /home/user3/mynewfile /home/user3/mynewfile2

Além disso, parece que você deseja copiar para $U3/CIT/grades/${File[2]} , para que não seja esquecido, mas adicione-o como uma linha adicional:

$ echo cp $NF1 $U3/CIT/grades/${File[2]}
cp /home/user3/mynewfile /home/user3/CIT/grades/mynewfile1
  • tudo ecoa os comandos cp que seriam executados
  • pode ser reescrito para direcionar os argumentos para usar xargs semelhante ao seu código original, mas isso realmente envolve mais digitação, então evitamos

Portanto, basta remover o echo neste exemplo de texto para criar a versão final do código.

    
por 02.10.2015 / 04:40
0

Eu não sei o que está errado com o script como está escrito; usando set -x como a segunda linha do script é um bom começo para depuração, como don_crissti apontou. Eu não sei xargs e expansão de array bem o suficiente para ver de relance o que está errado.

No entanto, , existe uma solução fácil, e é provavelmente a melhor maneira de resolver este problema : use apenas tee . Ele permite que você grave em vários arquivos em um comando, e ainda permite anexar texto em vez de substituir o conteúdo do arquivo (se é isso que você quer).

Se eu estou lendo o seu script corretamente, o que você quer seria algo como:

#!/bin/bash

NF1=/home/user3/mynewfile
U3=/home/user3/
File=(grades mynewfile mynewfile1 mynewfile2)

mkdir -p /home/user3/{CIT/{tests/,grades/},MyStuff/{Tests/,Labs/},NOS/};
cd ${U3}CIT/tests/
echo /etc/hosts.allow | tee ${File[*]} ${U3}CIT/grades/${File[2]} $NF1
cd -

EDIT: Expansão de array usa separação de espaço por padrão; portanto, adicionei um cd para que os arquivos "mynewfile, mynewfile1, mynewfile2" sejam criados em / home / user3 / CIT / tests em vez de no diretório de trabalho atual. (Existem, sem dúvida, maneiras mais limpas para fazer isso.)

    
por 02.10.2015 / 03:04