Prefixando e anexando blocos de texto a uma lista de arquivos

5

Estou tentando prefixar e anexar blocos de texto a uma lista de arquivos. Aqui é onde eu estou tão longe. O ponto de atrito é a linha sed -i "1i \$prefix" "$file" && . sed não substituirá o valor de prefix em. Tentei seguir vários tópicos sobre isso no unix.sx e em alguns outros lugares, mas fiquei com dor de cabeça.

Alguém pode me dizer como consertar isso? Se for muito complicado, estou bem em usar outra coisa em vez de sed .

Isso está intimamente relacionado a Como eu adiciono texto ao início e ao fim de vários arquivos de texto no Bash? , que é onde eu tenho o código abaixo. A diferença é que a questão não cobre a expansão de uma variável, e também no meu caso as strings em questão são multilinhas.

filelist=(foo.tex bar.tex)

prefix='\documentclass[12pt]{article}                                                                                                                                       
\usepackage{myarticle}                                                                                                                                                      
%\xpretocmd{\opening}{\insertname}{}{}                                                                                                                                      
\begin{document}                                                                                                                                                            
%\insertname                                                                                                                                                                
\begin{verbatim}'

suffix='\end{verbatim}                                                                                                                                                      
\end{document}'                                                                                                                                                                 

for file in "${filelist[@]}"; do
  sed -i "1i \$prefix" "$file" &&
  echo "$suffix" >> "$file"
done
    
por Faheem Mitha 24.01.2014 / 22:18

4 respostas

2

Como sobre (supondo que seu shell tenha uma substituição de processo):

for file in "${filelist[@]}"; do
    cat <(printf "%s" "$prefix") "$file" <(printf "%s" "$suffix") > "$file"_$$\ 
     && mv "$file"_$$ "$file"
done

ou melhor, em Perl (não testado):

perl -MTie::File -e '
    @ARGV//=<STDIN>;
    chomp(@ARGV);
    for(@ARGV){
        tie @lines,"Tie::File",$_;
        @lines=($ENV{prefix} @lines $ENV{suffix})
    }' "${filelist[@]}"

Para uma abordagem alternativa, se o prefixo e o sufixo forem corrigidos, veja a pergunta a seguir (que também é sobre (La) TeX :)):

por 24.01.2014 / 23:09
2

Com zsh:

zmodload zsh/mapfile
for i ($filelist) mapfile[$i]="$prefix
$mapfile[$i]$suffix
"

Com ksh93 ou bash (ou zsh ):

for file in "${filelist[@]}"; do
  {
    rm -- "$file" && {
      printf '%s\n' "$prefix"
      cat
      printf '%s\n' "$suffix"
    } > "$file"
  } < "$file"
done
    
por 24.01.2014 / 23:50
1

Aqui estão algumas opções, nenhuma das quais usa sed . Eu acho que, em geral, tentar fazer com que sed seja legal com variáveis externas raramente vale o esforço.

Shell

for file in "${filelist[@]}"; do 
  tmp=$(mktemp); 
  printf "%s\n%s\n%s\n" "$prefix" $(cat "$file") "$suffix" > "$tmp" && 
  mv "$tmp" "$file"; 
done

Perl / Shell

for file in "${filelist[@]}"; do 
  tmp=$(mktemp); 
  perl -lpe 'BEGIN{print $ENV{prefix}}END{print $ENV{suffix}}' $file 
  mv "$tmp" "$file"; 
done

Pure Perl

Este tem a vantagem de não depender de módulos externos:

perl -le 'foreach (@ARGV){
           open($f,"+<","$_"); @a=<$f>; 
           print $f "$ENV{suffix}\n@a$ENV{prefix}"
          }' "${filelist[@]}"

NOTA:

As variáveis precisam ser exportadas para que as soluções Perl funcionem, caso contrário, elas não estarão disponíveis no %ENV hash.

    
por 25.01.2014 / 17:22
1

O caso é semelhante a este: Anexando uma string contendo escapar personagem com sed

Sugiro a mesma resposta (adaptada):

for file in "${filelist[@]}"; do
  sed -i "1i\
$(echo -E "$prefix" | sed -e 's/\/\\/g' | sed -e '$! s/$/\/')" "$file" &&
  echo "$suffix" >> "$file"
done

O sed command i requer que cada linha, exceto a última, seja finalizada com uma barra invertida (isso estava faltando na resposta referida). Além disso, as barras invertidas precisam ser dobradas, portanto, sed não tentará interpretá-las. O echo produz o conteúdo da variável $prefix . Em seguida, no pipeline, o comando sed duplica as barras invertidas. O segundo comando sed adiciona barras invertidas no final de cada linha, exceto a última.

EDITAR Como funciona o programa sed $! s/$/\/ :

Primeiro, o endereço $ significa executar o comando que segue na última linha. $! nega isso, então o comando será executado em todas as linhas, exceto na última.

Em seguida, o comando s/// faz substituição. Ele substituirá a string vazia no final da linha, denotada por $ , por uma barra invertida. Mas a barra invertida é um caractere especial, por isso precisamos escapar dela com outra barra invertida para que sed a leia corretamente.

    
por 25.01.2014 / 02:25

Tags