Criando vários arquivos de entrada usando sed em um loop for

2

Suponha que eu tenha um arquivo de script simples do Mathematica chamado "a.m" que contenha o parâmetro 'a' sem valor atribuído:

Solve[x^2+5^a==0,x]>>a.out

O que eu gostaria de fazer é criar vários arquivos de script variando o valor 'a' digamos de 1 a 10 e nomear cada arquivo pelo valor correspondente de 'a' como 1.m, 2.m etc. Para isso, tentei usar o comando 'sed' em um loop for da seguinte maneira:

for ((i=1; i<=10; i++)); do sed 's/a/i/' <a.m >i.m;  done

para que, para cada valor fixo de i, substitua 'a' pelo valor numérico e crie um novo arquivo com o nome 'i.m'. No entanto, acima da linha cria um único arquivo de script chamado i.m com 'a' substituído por 'i'. Alguma sugestão ?

    
por user91411 04.03.2015 / 22:23

2 respostas

1

Scripts shell contêm muitas strings literais (nomes de comandos, nomes de arquivos, etc.), portanto, usar o valor de uma variável requer que um caractere indique explicitamente que é uma referência variável: consiste em $ seguido pelo nome da variável (em sua forma mais simples). Em geral, você precisa duplicar aspas em torno da substituição de variáveis . Dentro de aspas simples, as variáveis não são expandidas de todo (a $ inside '…' apenas significa si mesma). Assim:

for ((i=1; i<=10; i++)); do
  sed "s/a/$i/" <a.m >"$i.m"
done

Dentro dos parênteses duplos, você não precisa de cifrões porque os parênteses duplos delimitam expressões aritméticas, e não há strings em expressões aritméticas, então uma palavra nua é interpretada como uma variável para desreferenciar.

Observe que o comando sed substitui o primeiro caractere a no arquivo de modelo. Você pode querer escolher um nome de variável que tenha menos chance de ocorrer em algo como um nome de função. Como alternativa, você pode gerar uma atribuição no início do script:

for ((i=1; i<=10; i++)); do
  echo "a=$i;" >"$i.m"
  cat a.m >>"$i.m"
done

O operador de redirecionamento >> é anexado ao arquivo existente , em contraste com > que trunca o arquivo se ele existir. / p>     

por 05.03.2015 / 02:17
1

Acho que seria um erro chamar muitos sed s, onde apenas um fará. A alegação de sed para a fama é sua capacidade de fazer o loop de forma eficiente na entrada e modificá-la em uma saída diferente, mas também pode lidar com saídas múltiplas com muita facilidade. Aqui, por exemplo, é uma re-escrita POSIX portátil (e muito mais eficiente) do seu for loop:

echo "Solve[x^2+5^a==$((a=0)),x]>>a.out" >/tmp/i.m    ###create file + init $a
until [ "$((a+=1))" -gt 10 ]                          ###iterate + test
do    printf "h;s/a/$a/gpw /tmp/$a.m\ng;"             ###push new sed command
done| sed -nf - /tmp/i.m                              ###read + apply commands
head /tmp/[0-9].m /tmp/10.m                           ###print results

sed pode ler seu script de stdin e aplicá-lo a um arquivo nomeado - que é o que a instrução sed -nf - /tmp/i.m faz. Ele também pode, simultaneamente, p rint sua saída para stdout e w rite sua saída para um ou mais arquivos nomeados. À medida que o loop de shell funciona, ele imprime linhas em sed , que, quando concluídas, equivalem a:

h;s/a/1/gpw /tmp/1.m
g;h;s/a/2/gpw /tmp/2.m
g;h;s/a/3/gpw /tmp/3.m
g;h;s/a/4/gpw /tmp/4.m
g;h;s/a/5/gpw /tmp/5.m
g;h;s/a/6/gpw /tmp/6.m
g;h;s/a/7/gpw /tmp/7.m
g;h;s/a/8/gpw /tmp/8.m
g;h;s/a/9/gpw /tmp/9.m
g;h;s/a/10/gpw /tmp/10.m
g

Que informa sed para ...

  1. Sobrescreve seu buffer h old com uma cópia de seu buffer de edição.
  2. g lobally s/// ubstitua todas as ocorrências da letra a em seu buffer de edição com qualquer valor atual da variável $a .
  3. Ao mesmo tempo, os dois p rinting os resultados dessa s/// ubstitution para stdout e w os resultados para o arquivo chamado /tmp/$a.m , em que $a é iterável.
  4. E durar para g et o buffer de retenção sobrescrevendo o buffer de edição.

sed aplicará essa sequência para cada linha em seu arquivo de entrada nomeado. Quando for chamado pela primeira vez, truncará cada um de seus arquivos com nome w rite, mas depois anexará cada ação w rite a cada arquivo de saída em seqüência. Como tenho apenas uma linha em i.m , porém, sed imprime:

Solve[x^2+5^1==0,x]>>1.out
Solve[x^2+5^2==0,x]>>2.out
Solve[x^2+5^3==0,x]>>3.out
Solve[x^2+5^4==0,x]>>4.out
Solve[x^2+5^5==0,x]>>5.out
Solve[x^2+5^6==0,x]>>6.out
Solve[x^2+5^7==0,x]>>7.out
Solve[x^2+5^8==0,x]>>8.out
Solve[x^2+5^9==0,x]>>9.out
Solve[x^2+5^10==0,x]>>10.out

E head , lendo cada um dos dez arquivos recém-criados em /tmp , imprime:

==> /tmp/1.m <==
Solve[x^2+5^1==0,x]>>1.out

==> /tmp/2.m <==
Solve[x^2+5^2==0,x]>>2.out

==> /tmp/3.m <==
Solve[x^2+5^3==0,x]>>3.out

==> /tmp/4.m <==
Solve[x^2+5^4==0,x]>>4.out

==> /tmp/5.m <==
Solve[x^2+5^5==0,x]>>5.out

==> /tmp/6.m <==
Solve[x^2+5^6==0,x]>>6.out

==> /tmp/7.m <==
Solve[x^2+5^7==0,x]>>7.out

==> /tmp/8.m <==
Solve[x^2+5^8==0,x]>>8.out

==> /tmp/9.m <==
Solve[x^2+5^9==0,x]>>9.out

==> /tmp/10.m <==
Solve[x^2+5^10==0,x]>>10.out
    
por 05.03.2015 / 19:54