我讨厌用许可/归属注释弄乱我的源代码文件,但有时这是一个要求。因此,编写了数十个源代码文件(组织在子目录树中),我需要在每个文件的开头添加相同的多行注释。
我怀疑使用标准 GNU/Linux 命令行工具来完成这项任务非常简单,尽管我不太熟练地认真使用它们,所以请您原谅并寻求您的帮助。
我需要的是将每个theTargetFile.txt
in ./*.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
或-print0
find 选项,该选项可能不适用于所有系统:
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" \;