디렉터리 및 해당 하위 디렉터리의 모든 텍스트 파일에 특정 텍스트 파일 내용을 추가하는 방법은 무엇입니까?

디렉터리 및 해당 하위 디렉터리의 모든 텍스트 파일에 특정 텍스트 파일 내용을 추가하는 방법은 무엇입니까?

나는 라이센스/귀속 주석으로 소스 코드 파일을 복잡하게 만드는 것을 싫어하지만 때로는 요구 사항이 될 때도 있습니다. 따라서 수십 개의 소스 코드 파일이 작성되고(하위 디렉터리 트리에 구성됨) 각 파일의 시작 부분에 동일한 여러 줄 주석을 추가해야 합니다.

표준 GNU/Linux 명령줄 도구를 사용하여 이 작업을 수행하는 것이 매우 간단하다고 생각합니다. 비록 제가 이 도구를 진지하게 사용하는 데는 그다지 능숙하지 않기 때문에 양해를 구하고 도움을 요청합니다.

나에게 필요한 것은 모든 theTargetFile.txtin ./*.txt(하위 디렉토리의 재귀 포함)을 cat theCommonComment.txt theTargetFile.txt.

또한 특정 마스크에 맞는 파일을 제외하고 싶습니다. 예를 들어 모든 파일을 고려 *.txt하되 그대로 두십시오 *.DontTouch.txt.

find내 생각에 나에게 정말로 필요한 가장 어려운 부분은 하위 디렉터리를 실행하고, *.txt파일을 포함하고, 파일을 제외하는 멋진 기반 주문이라고 생각합니다 *.DontTouch.txt.

답변1

제가 생각할 수 있는 가장 간단한 방법은 GNU를 사용하는 find것 입니다 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또는 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파일이 재귀 작업을 수행 중인 디렉터리에 없는지 확인하세요(또는 적어도 조회에서 제외되었는지 확인하세요). 그렇지 않으면 일부 파일에 대해 두 개의 헤더가 생성됩니다.

고쳐 쓰다

마지막 생각은 헤더가 파일에 추가되었는지 확인하고 싶을 수도 있다는 것입니다. 이는 새 파일을 추가하고 명령을 다시 실행해야 하는 경우 유용할 수 있습니다. 또한 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"  \;

관련 정보