파일이없는 경우에만 파일에 행 추가


157

구성 파일의 끝에 다음 줄을 추가해야합니다.

include "/configs/projectname.conf"

라는 파일에 lighttpd.conf

나는 sed이것을하기 위해 사용 하려고 노력하고 있지만 어떻게 해결할 수는 없다.

줄이 아직 없으면 어떻게 삽입합니까?


당신은 INI 파일을 편집하려는 경우 도구는 crudini(그러나 lighthttpd 아직에 대한) 좋은 옵션이 될 수있다
rubo77

답변:


291

간단하게 유지하십시오 :)

grep + echo로 충분합니다 :

grep -qxF 'include "/configs/projectname.conf"' foo.bar || echo 'include "/configs/projectname.conf"' >> foo.bar

편집 : 통합 @cerin 및 @ thijs-wouters 제안 .


2
출력을 억제하기 위해 grep에 -q 스위치를 추가합니다. grep -vq ...
Dave Kirby

1
참고로 -v 및 &&를 사용하면 트릭을 수행하지 않지만 || -v없이 작동합니다.
bPizzi

3
이것은 매우 간단한 라인에서만 작동합니다. 그렇지 않으면 grep은 행에서 대부분의 알파벳이 아닌 문자를 패턴으로 해석하여 파일에서 행을 감지하지 못합니다.
Cerin

2
아름다운 솔루션. 이것은 물론 더 복잡한 표현을 트리거하는 데에도 효과적입니다. 내는를 사용하여 여러 echo줄의 catheredoc을 구성 파일로 트리거 합니다.
Eric L.

2
-s파일이 존재하지 않을 때 오류를 무시하고 해당 줄만있는 새 파일을 작성하려면 추가하십시오 .
Frank

78

이것은 사용하여 깨끗하고 읽기 쉽고 재사용 가능한 솔루션을 것 grep하고 echo이미 존재하지 않는 경우에만 파일에 줄을 추가 :

LINE='include "/configs/projectname.conf"'
FILE='lighttpd.conf'
grep -qF -- "$LINE" "$FILE" || echo "$LINE" >> "$FILE"

전체 라인 사용과 일치해야하는 경우 grep -xqF

-s파일이 존재하지 않을 때 오류를 무시하고 해당 줄만있는 새 파일을 작성하려면 추가하십시오 .


5
루트 권한이 필요한 파일 인 경우 :sudo grep -qF "$LINE" "$FILE" || echo "$LINE" | sudo tee -a "$FILE"
nebffa

행이로 시작하면 실제로 작동하지 않습니다 -.
hyperknot

@zsero : 좋은 지적입니다! --grep 명령을 추가 했으므로 대시로 시작하는 $ LINE을 더 이상 옵션으로 해석하지 않습니다.
rubo77

13

sed버전은 다음과 같습니다 .

sed -e '\|include "/configs/projectname.conf"|h; ${x;s/incl//;{g;t};a\' -e 'include "/configs/projectname.conf"' -e '}' file

문자열이 변수에있는 경우 :

string='include "/configs/projectname.conf"'
sed -e "\|$string|h; \${x;s|$string||;{g;t};a\\" -e "$string" -e "}" file

부분 문자열을 전체 / 업데이트 된 구성 파일 항목으로 sed -i -e '\|session.*pam_mkhomedir.so|h; ${x;s/mkhomedir//;{g;tF};a\' -e 'session\trequired\tpam_mkhomedir.so umask=0022' -e '};:F;s/.*mkhomedir.*/session\trequired\tpam_mkhomedir.so umask=0022/g;' /etc/pam.d/common-session
바꾸거나

좋았어요. +1이 많이 도움이되었습니다. sed 표현을 설명해 주시겠습니까?
Rahul

이 솔루션에 대한 주석이 달린 설명을보고 싶습니다. 나는 sed수년간 사용 했지만 대부분 s명령 만 사용 했습니다 . holdpattern공간 스왑은 내 능력 밖입니다.
nortally

11

보호 된 파일에 쓰는 경우 @drAlberT 및 @ rubo77의 답변은 sudo 할 수 없으므로 작동하지 않을 수 있습니다 >>. 유사 간단한 해결책은 , 다음, 사용하는 것입니다 tee --append(맥 OS에, 또는 tee -a) :

LINE='include "/configs/projectname.conf"'
FILE=lighttpd.conf
grep -qF "$LINE" "$FILE"  || echo "$LINE" | sudo tee --append "$FILE"

6

언젠가 다른 사람 이이 코드를 "레거시 코드"로 처리 해야하는 경우 다음과 같이 덜 이질적인 코드를 작성하면 그 사람에게 감사하게 될 것입니다.

grep -q -F 'include "/configs/projectname.conf"' lighttpd.conf
if [ $? -ne 0 ]; then
  echo 'include "/configs/projectname.conf"' >> lighttpd.conf
fi

1
쉘을 모른다면 Windows를 관리하십시오. && 및 ||를 사용하는 솔루션 일반적인 셸 구문이며 유능한 관리자가 이해해야합니다. 전혀 난해한 것이 없습니다.
Graham Nicholls

3
귀하의 의견 Graham에 감사드립니다! 예, 일반적인 쉘 구문입니다. 그리고 모든 유능한 관리자가 그것을 이해해야합니다. 그러나 셸 내에서 식 평가 알고리즘의 부작용을 기반으로 작동합니다. 그래서 당신은 내 원래의 요점 인 직설을 제외하고 당신이 원하는대로 부를 수 있습니다.
Marcelo Ventura


6

또 다른 sed 솔루션은 항상 마지막 줄에 추가하고 기존의 것을 삭제하는 것입니다.

sed -e '$a\' -e '<your-entry>' -e "/<your-entry-properly-escaped>/d"

"적절하게 이스케이프 처리됨"은 항목과 일치하는 정규식을 배치하는 것, 즉 실제 항목에서 모든 정규식 컨트롤을 이스케이프 처리하는 것, 즉 ^ $ / *? + () 앞에 백 슬래시를 두는 것을 의미합니다.

이것은 파일의 마지막 줄에서 실패하거나 줄 바꿈이 없으면 확실하지 않지만 일부 멋진 분기로 처리 할 수 ​​있습니다.


1
짧고 읽기 쉬운 멋진 원 라이너. etc / hosts 업데이트 sed -i.bak -e '$a\' -e "$NEW_IP\t\t$HOST.domain\t$HOST" -e "/.*$HOST/d" /etc/hosts
Noam Manos

더 작은 버전 :sed -i -e '/<entry>/d; $a <entry>'
Jérôme Pouiller

@Jezz 항목이 이미 파일의 끝에 있으면 d명령이 sed 프로그램을 다시 시작 a하여 삭제가 마지막 행에있는 경우 ppend 를 건너 뛰기 때문에 이것이 실패한다고 생각합니다 .
Robin479

@ Robin479 젠장, a보류하기 전에 실행해야 d합니다 : sed -i -e '$a<entry>' -e '/<entry>/d'. 원래 답변과 거의 동일합니다.
Jérôme Pouiller

3

awk를 사용하십시오

awk 'FNR==NR && /configs.*projectname\.conf/{f=1;next}f==0;END{ if(!f) { print "your line"}} ' file file

'file file'입니까 아니면 'file'입니까?
webdevguy

그것은의 file file이 같은 파일을 통해 두 개의 패스를 수 있기 때문이다. NR==FNR첫 번째 패스에는 적용되지만 두 번째 패스에는 적용되지 않습니다. 이것은 일반적인 Awk 관용구입니다.
tripleee

1

grep을 사용한 답변이 잘못되었습니다. 전체 행을 일치 시키려면 -x 옵션을 추가해야합니다. 그렇지 않으면 #text to add정확하게 추가 할 때 와 같은 행 이 여전히 일치합니다 text to add.

올바른 해결책은 다음과 같습니다.

grep -qxF 'include "/configs/projectname.conf"' foo.bar || echo 'include "/configs/projectname.conf"' >> foo.bar

1

sed 사용 : 줄 끝에 삽입합니다. 물론 평소대로 변수를 전달할 수도 있습니다.

grep -qxF "port=9033" $light.conf
if [ $? -ne 0 ]; then
  sed -i "$ a port=9033" $light.conf
else
    echo "port=9033 already added"
fi

oneliner sed 사용

grep -qxF "port=9033" $lightconf || sed -i "$ a port=9033" $lightconf

echo를 사용하면 루트에서는 작동하지 않지만 다음과 같이 작동합니다. 그러나 암호를 요구할 수 있기 때문에 원하는 작업을 자동화하지 못합니다.

특정 사용자의 루트에서 편집하려고 할 때 문제가 발생했습니다. $username이전을 추가하는 것이 나를 위해 수정되었습니다.

grep -qxF "port=9033" light.conf
if [ $? -ne 0 ]; then
  sudo -u $user_name echo "port=9033" >> light.conf
else
    echo "already there"    
fi

stackoverflow에 오신 것을 환영합니다! 답변을 게시하기 전에 질문을주의 깊게 읽으십시오. OP는 sed를 사용하여 삽입하는 방법을 물었습니다
Markoorn

-1

필요한 쓰기 권한이 제한된 파일을 편집해야했습니다 sudo. ghostdog74의 답변에서 작업하고 임시 파일을 사용하십시오.

awk 'FNR==NR && /configs.*projectname\.conf/{f=1;next}f==0;END{ if(!f) { print "your line"}} ' file > /tmp/file
sudo mv /tmp/file file

이것은 올바르게 보이지 않으며 구성 줄이 없으면 파일에서 다른 줄을 잃게됩니다.
tripleee 2012 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.