파일에 줄이 없으면 어떻게 파일에 여러 줄을 추가할 수 있나요?

파일에 줄이 없으면 어떻게 파일에 여러 줄을 추가할 수 있나요?

파일에 줄이 없으면 어떻게 파일에 여러 줄을 추가할 수 있나요?

예를 들어 여러 전역 별칭을 추가하려면 /etc/bash.bashrc다음을 사용합니다 .여기 문서:

cat <<-"BASHRC" >> /etc/bash.bashrc
    alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
    alias brc="nano /etc/bash.bashrc"
BASHRC

이 작업에는 행이 이미 존재하는지 확인하는 방법이 포함되어 있지 않으며 실수로 이 문서를 다시 실행하면 중복 및 충돌이 발생할 수 있다는 비판을 받았습니다.

답변1

파일의 행을 newdata에 추가하는 간단한 쉘 스크립트입니다 datafile. newdata이 문서를 변경하는 것은 간단해야 합니다. 이는 grep모든 (새로운) 입력 라인이 필요하기 때문에 실제로 매우 효율적이지 않습니다.

target=datafile
while IFS= read -r line ; do
    if ! grep -Fqxe "$line" "$target" ; then
        printf "%s\n" "$line" >> "$target"
    fi
done < newdata 

각 줄에 대해 이를 사용하여 고정 문자열 일치(정규식 없음), 전체 줄 일치 및 일치하는 줄의 출력을 억제하기 위해 grep대상 파일에 이미 존재하는지 확인합니다 . 일치하는 라인이 없으면 거짓 오류 코드가 반환되므로, 부정적인 결과가 참이면 대상 파일에 추가하십시오.-F-x-qgrep


에서는 보다 효율적으로 임의의 행을 배열의 키로 처리할 수 있어야 합니다 awk.awk

$ awk 'FNR == NR { lines[$0] = 1; next } ! ($0 in lines) {print}' datafile newdata 

첫 번째 부분은 FNR == NR { lines[$0] = 1; next }첫 번째 입력 파일의 모든 행을 (연관) 배열의 키로 로드합니다 lines. 두 번째 부분은 ! ($0 in lines) {print}다음 입력 라인에서 작동하며 해당 라인이 배열에 없으면 "새" 라인을 인쇄합니다.

생성된 출력에는 새 줄만 포함되므로 원본 파일에 추가해야 합니다. 예 sponge:

$ awk 'FNR == NR { lines[$0] = 1; next } ! ($0 in lines) {print}' datafile newdata | sponge -a datafile

또는 awk다음 줄을 마지막 줄에 추가할 수 있습니다. 이렇게 하려면 파일 이름을 다음으로 전달하면 됩니다 awk.

$ target=datafile 
$ awk -vtarget="$target" 'FNR == NR { lines[$0] = 1; next } 
                        ! ($0 in lines) {print >> target}' "$target" newdata

here-doc를 사용하려면 리디렉션을 설정하는 것 외에도 awk(stdin)을 명시적 소스 파일로 추가해야 합니다.-awk ... "$target" - <<EOF

답변2

이 솔루션은 여러분이 생각하는 것과 약간 다를 수 있지만 별칭이 실제로 정의되어 있는지 확인하고 그렇지 않은 경우 bashrc에 추가하면 됩니다. 비교적 최신 버전의 Bash를 사용한다고 가정하면 ...

# instead of 'alias x=y' form put them in an associative array
declare -A aliases
aliases['a']='apple'
aliases['ba']='banana'

for key in "${!aliases[@]}"; do
    if ! alias "$key" > /dev/null 2>&1; then
        printf "alias %s='%s'\n" "$key" "${aliases[$key]}" >> /etc/bash.bashrc
    fi
done

unset aliases key

. ./scriptname일반 스크립트로 실행하는 대신 가져옵니다 .

노트:후보 별칭이 많이 있고 이를 연관 배열 형식으로 수동으로 변환하는 것이 조심스러운 경우 다음을 vim사용하여 파일을 편집하고 이 명령을 실행할 수 있습니다 :%s/\valias *([^=]+)\=['"]?([^'"]+)['"]?$/aliases['\1']='\2'/.

또는후보 별칭(다른 것은 제외)을 파일(예: /tmp/aliases.txt) 에 넣고 aliases[..]='..'스크립트의 줄을 다음으로 바꿉니다.

while IFS= read -r a; do 
    eval "$a"; 
done < <(sed -E "s/alias  *([^=]+)=['\"]?([^'\"]+)['\"]?$/aliases['\1']='\2'/" /tmp/aliases.txt)

물론 AA를 사용하는 것 외에 다른 방법도 있지만 깨끗하고 사용하기 쉽습니다. 이제 AA를 사용하고 싶습니다. :)

답변3

정확한 일치를 위한 일반적인 솔루션(성능에 최적화되지 않음) 이 파일에는 input확인할 줄이 포함되어 있습니다.

awk 'FNR==NR { lines[NR]=$0; next; };
    { for(i=1;i<=length(lines);i++) if ($0==lines[i]) matches[i]=1; print; };
    END { for(i=1;i<=length(lines);i++)
        if (matches[i]==0) print lines[i]; }' input file

시험:

:> cat input
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
alias brc="nano /etc/bash.bashrc"

:> cat file
a
b
c
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
d

명령의 출력은 다음과 같습니다 awk.

a
b
c
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
d
alias brc="nano /etc/bash.bashrc"

답변4

어 허. 이건 어때...

추가하려는 별칭을 파일에 넣으십시오.새로운. 그 다음에...

cp bashrc bashrc.tmp && comm -23 <(sort -u new) <(sort -u bashrc.tmp) >> bashrc && rm -f bashrc.tmp

새로운 별칭에 대해 이 작업을 수행하고bashrc콘텐츠(추가할 때 경쟁 조건을 피하기 위해 임시 파일에 넣기)bashrc) 그리고 실행하세요 comm. comm정렬된 파일을 한 줄씩 비교하고 고유하고 일반적인 줄을 표시합니다. 열 2와 3( -23)을 표시하지 않으므로 결과는 해당 고유 행만 표시됩니다.새로운우리는 그것들을 다음에 추가합니다bashrc. 그게 다야.

(이것은 더 많은 "하나의 라이너"에 대한 탐구에 초점을 맞춘 다른 답변과는 완전히 다른 접근 방식입니다.)

관련 정보