如何将特定的文本文件内容添加到目录及其子目录中的每个文本文件?

如何将特定的文本文件内容添加到目录及其子目录中的每个文本文件?

我讨厌用许可/归属注释弄乱我的源代码文件,但有时这是一个要求。因此,编写了数十个源代码文件(组织在子目录树中),我需要在每个文件的开头添加相同的多行注释。

我怀疑使用标准 GNU/Linux 命令行工具来完成这项任务非常简单,尽管我不太熟练地认真使用它们,所以请您原谅并寻求您的帮助。

我需要的是将每个theTargetFile.txtin ./*.txt(包括递归地在子目录中)替换为cat theCommonComment.txt theTargetFile.txt.

我还希望排除适合特定更具体掩码的文件,例如考虑所有文件*.txt但保持*.DontTouch.txt完整。

我认为我真正需要的最难的部分是一个基于花式find的咒语,它将运行子目录、包含*.txt文件和排除*.DontTouch.txt文件。

答案1

我能想到的最直接的方法是使用GNUfind以及bash来自sponge更多实用程序:

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-print0find 选项,该选项可能不适用于所有系统:

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文件不在您正在执行递归操作的目录中(或者至少确保它被排除在查找之外),否则您最终会得到两个标头一些文件。

更新

最后一个想法是,您可能想要检查标头是否已添加到文件中。如果您添加新文件并必须再次运行该命令,这可能很有用。它还解决了将theCommonComment.txt文件放在搜索路径中的问题。这两个解决方案将变成:

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"  \;

相关内容