Como prefixar um conteúdo de arquivo de texto específico para cada arquivo de texto em um diretório e seus subdiretórios?

6

Eu odeio confundir meus arquivos de código-fonte com comentários de atribuição / licenciamento, mas algumas vezes é um requisito. Então, tendo dezenas de arquivos de código-fonte (organizados em uma árvore de subdiretórios) escritos, preciso adicionar o mesmo comentário de várias linhas ao início de cada um deles.

Eu suspeito que esta é uma tarefa muito fácil de se fazer com as ferramentas padrão de linha de comando do GNU / Linux, embora eu não seja proficiente em fazer qualquer uso sério delas, então peço perdão e peço sua ajuda.

O que eu preciso é substituir cada theTargetFile.txt em ./*.txt (inclusive em subdiretórios de forma recursiva) por algo como cat theCommonComment.txt theTargetFile.txt .

Eu também preferiria excluir arquivos que se encaixam em uma máscara específica, como considerar todos os *.txt , mas deixar *.DontTouch.txt intacta.

Eu acho que a parte mais difícil do que eu realmente preciso é uma fantasia find -based spell que iria rodar através de subdiretórios, incluir *.txt files e excluir *.DontTouch.txt files.

    
por Ivan 18.04.2014 / 19:33

6 respostas

7

A maneira mais direta que vejo para fazer isso é com o GNU find , bash e o utilitário sponge de moreutils :

find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -print0 |
  while IFS= read -rd '' file; do
    echo 'cat path/to/theCommonComment.txt "$file" | sponge "$file"'
  done

Como está, isso apenas imprimirá os comandos cat / sponge sem realmente fazer nada. Quando tiver certeza de que você tem o que deseja, é possível remover o eco e as aspas simples ao redor do comando.

Sem usar sponge ou a opção -print0 para encontrar os itens que podem não estar disponíveis em todos os sistemas:

find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -exec sh '
  for file; do
    tempfile=$(mktemp)
    cat path/to/theCommonComment.txt "$file" >"$tempfile"
    mv "$tempfile" "$file"
  done
  ' sh {} +

Não há uma maneira fácil de parar este simplesmente imprimir o que vai fazer, por isso tenha cuidado. Uma coisa a observar - certifique-se de que seu arquivo theCommonComment.txt não está no diretório em que você está executando a operação recursiva (ou pelo menos certifique-se de que ele seja excluído da localização), senão você terminará com dois os cabeçalhos em alguns arquivos.

Atualizar

Um último pensamento é que você pode querer verificar se o cabeçalho já foi adicionado ao arquivo. Isso pode ser útil se você adicionar novos arquivos e tiver que executar o comando novamente. Ele também contorna o problema de ter o arquivo theCommonComment.txt no caminho de pesquisa. As duas soluções se tornariam:

comment_file=path/to/theCommonComment.txt
size=$(wc -c "$comment_file")

find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -print0 |
  while IFS= read -rd '' file; do
    if [ cmp -n "$size" $comment_file" "$file" ]; do
      echo 'cat "$comment_file" "$file" | sponge "$file"'
    fi
  done
export comment_file=path/to/theCommonComment.txt
export size=$(wc -c "$comment_file")

find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -exec sh '
  for file; do
    if [ cmp -n "$size" $comment_file" "$file" ]; do
      tempfile=$(mktemp)
      cat "$comment_file" "$file" >"$tempfile"
      mv "$tempfile" "$file"
    fi
  done
  ' sh {} +
    
por 18.04.2014 / 21:19
3

No GNU / qualquer coisa, para inserir _after_ a primeira linha:

find -name '*.txt' ! -name '*thispattern*' ! -name '*thatpattern*' \
  -exec sed -si '1r TheLicense.txt' '{}' +

para inserir um arquivo antes, o mais simples é um pouco mais lento e um pouco mais claudicante:

find -name '*.txt' ! -name '*thispattern*' ! -name '*thatpattern*' \
  -exec sed -si '1{h;s,.*,cat TheLicense.txt,ep;g}' '{}' +
    
por 18.04.2014 / 22:23
3

com zsh :

zmodload zsh/mapfile
setopt extendedglob # best in ~/.zshrc

for f (Dir/**/(^*DontTouch).txt(N.)) 
  mapfile[$f]=$mapfile[theCommonComment.txt]$mapfile[$f]
    
por 19.04.2014 / 09:19
1

Eu criaria um arquivo como dummy com o conteúdo que você deseja substituir. Então, o arquivo dummy ficaria abaixo.

<?php
 /**
  *
  * Copyright (C) MyCompany, Ltd. - All Rights Reserved
  * Unauthorized copying of this file, via any medium is strictly prohibited
  * Proprietary and Confidential
  * 
  *
  */

Depois disso, eu executaria o script abaixo.

for f in ./*; do
sed -i '/<?php/{
    s/<?php//g
    r dummy
}' $f
done

Estou substituindo o <?php por espaços e substituindo-o pelo conteúdo do arquivo dummy .

Claro, você pode modificar o código acima para atender às suas necessidades.

No entanto, existe uma maneira muito mais sofisticada de fazer isso.

for f in *; do 
  echo "whatever" > tmpfile
  cat $f >> tmpfile
  mv tmpfile $f
done

A resposta acima foi tirada de aqui . Você está basicamente colocando o conteúdo primeiro em um arquivo tmp e, em seguida, adicionando o conteúdo original ao arquivo tmp. Agora depois disso, você está renomeando o arquivo tmp de volta para o nome do arquivo original.

    
por 18.04.2014 / 19:37
0

Esta solução usa bash, find, tac e sed.

Copie o seguinte script em um arquivo e torne o arquivo executável: chmod +x script

Em seguida, use da seguinte forma:

./script <DIR> <HEADERFILE>

Onde

<DIR> The directory containing files ( or directory containing files..)
<HEADERFILE> The file to add on top of each file

Este é o script:

#!/bin/bash

# inset a file content at the beginning of each matching files

DIR=$1
HEADER_FILE=$2

#the matching files will be ignored

IGNORE_FILE="*.DontTouch.txt"

insertHeader(){
   local targetfile=$1
   local headerfile=$2
   echo "$targetfile"
   while read line
    do
#          echo $line
           sed -i "$targetfile" -e "1i$line\ "
    done< <(tac "$headerfile")

}

export -f insertHeader
find "$DIR" -type f -name "*.txt" ! -name "$IGNORE_FILE" -exec bash -c "insertHeader {} $HEADER_FILE"  \;
    
por 18.04.2014 / 22:21
-1

Esta solução aproveitará os comandos find e xargs:

find . -name "*.txt" -a ! -name "*.DontTouch.txt" -print | xargs -n 1 cat theCommonComment.txt
    
por 03.08.2016 / 17:53