ディレクトリとそのサブディレクトリのすべてのテキストファイルに特定のテキストファイルの内容を追加するには?

ディレクトリとそのサブディレクトリのすべてのテキストファイルに特定のテキストファイルの内容を追加するには?

私はライセンス/帰属コメントでソースコードファイルを複雑にするのが嫌いですが、時には要件になることもあります。したがって、数十のソースコードファイルが作成され(サブディレクトリツリーに構成されている)、各ファイルの先頭に同じ複数行コメントを追加する必要があります。

標準のGNU / Linuxコマンドラインツールを使用してこれを行うのは非常に簡単だと思います。私はこのツールを真剣に使用するのはあまりうまくいかないので、理解して助けを求めます。

私に必要なのは、すべてのtheTargetFile.txtin ./*.txt(サブディレクトリの再帰を含む)をcat theCommonComment.txt theTargetFile.txt

また、特定のマスクに合ったファイルを除外したいと思います。たとえば、すべてのファイルを考慮しますが、そのままにして*.txtください*.DontTouch.txt

find私の考えに私にとって本当に必要な最も難しい部分は、サブディレクトリを実行し、*.txtファイルを含め、ファイルを除外する素晴らしいベースの注文だと思います*.DontTouch.txt

答え1

私が考えることができる最も簡単な方法はGNUを使用するfindことですbashspongeその他のユーティリティ:

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

現時点では実際に何もせずにcat/コマンドだけを印刷します。sponge必要なものがわからない場合は、コマンドの周囲のエコーと一重引用符を削除できます。

spongeまたは、findオプションを使用しないと、-print0このオプションがすべてのシステムで機能しない可能性があります。

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 {} +

これを止める簡単な方法はありません。実行するジョブを印刷するだけですので注意してください。注意点 -theCommonComment.txtファイルが再帰操作を実行しているディレクトリにないことを確認してください(または少なくともルックアップから除外されていることを確認してください)。それ以外の場合、一部のファイルに対して2つのヘッダーが生成されます。

修正する

最後の考えは、ヘッダーがファイルに追加されたことを確認したいかもしれないということです。これは、新しいファイルを追加してコマンドを再実行する必要がある場合に便利です。また、theCommonComment.txt検索パスにファイルを配置する問題も解決します。これら2つの解決策は次のとおりです。

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 {} +

答え2

GNU /すべてのものの最初の行の後に挿入するには:

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

以前にファイルを挿入する最も簡単な方法は、少し遅く、少し混乱しています。

find -name '*.txt' ! -name '*thispattern*' ! -name '*thatpattern*' \
  -exec sed -si '1{h;s,.*,cat TheLicense.txt,ep;g}' '{}' +

答え3

そしてzsh

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

for f (Dir/**/(^*DontTouch).txt(N.)) 
  mapfile[$f]=$mapfile[theCommonComment.txt]$mapfile[$f]

答え4

このソリューションはbash、find、tac、およびsedを使用します。

次のスクリプトをファイルにコピーし、ファイルを実行可能にします。chmod +x script

次に、次のように使用します。

./script <DIR> <HEADERFILE>

どこ

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

スクリプトは次のとおりです。

#!/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"  \;

関連情報