이 bash 스크립트가 있습니다.
sed -i -r '/deb http\:\/\/httpredir\.debian\.org\/debian jessie main/d' /etc/apt/sources.list
sed -i -r '/deb http\:\/\/httpredir\.debian\.org\/debian jessie\-updates main/d' /etc/apt/sources.list
sed -i -r '/deb http\:\/\/security\.debian\.org jessie\/updates main/d' /etc/apt/sources.list
echo -e 'deb http://httpredir.debian.org/debian stable main contrib non-free\ndeb-src http://httpredir.debian.org/debian stable main contrib non-free\ndeb http://httpredir.debian.org/debian jessie-backports main contrib non-free\ndeb-src http://httpredir.debian.org/debian jessie-backports main contrib non-free\ndeb http://httpredir.debian.org/debian jessie-updates main contrib non-free\ndeb-src http://httpredir.debian.org/debian jessie-updates main contrib non-free\ndeb http://security.debian.org jessie/updates main contrib non-free\ndeb-src http://security.debian.org jessie/updates main contrib non-free' >> /etc/apt/sources.list
이 시퀀스를 실행하면 문제가 없으며 일치하는 줄이 데비안 소스 목록 파일에서 제거됩니다. 하지만 먼저 에코하면 행을 삭제하는 대신 행 5-7도 삭제됩니다.
SPACE를 \s로 변경해도 도움이 되지 않습니다.
이는 나중에 Dockerfile이 충분히 빠르게 업데이트되지 않고 Debian이 새로운 마이너 버전을 릴리스할 때 문제를 일으킬 수 있습니다.
이 정규식에 전역 라벨이 적용되는 것 같습니다. 줄의 시작과 끝을 정의하는 것은 bash에도 도움이 되지 않습니다(비록 regexr에서는 잘 작동하지만 그것이 제가 얻고 싶은 것입니다). http://regexr.com/3b910
sed를 사용하여 /igm 플래그를 정의할 수 없는 것 같습니다. sed는 여전히 전체 일치 행을 삭제합니다.
편집: 이 방법으로 단축했지만 파일의 모든 내용이 삭제되었기 때문에 잘못한 것입니다.
sed /etc/apt/sources.list -i -e '\!deb http://httpredir\.debian\.org/debian jessie main$!d' -e '\!deb http://httpredir\.debian\.org/debian jessie-updates main$!d' -e '\!deb http://security\.debian\.org jessie/updates main$!d' -e '$a \ndeb http://httpredir.debian.org/debian stable main contrib non-free\ndeb-src http://httpredir.debian.org/debian stable main contrib non-free\ndeb http://httpredir.debian.org/debian jessie-backports main contrib non-free\ndeb-src http://httpredir.debian.org/debian jessie-backports main contrib non-free\ndeb http://httpredir.debian.org/debian jessie-updates main contrib non-free\ndeb-src http://httpredir.debian.org/debian jessie-updates main contrib non-free\ndeb http://security.debian.org jessie/updates main contrib non-free\ndeb-src http://security.debian.org jessie/updates main contrib non-free'
다음은 문제에 대한 수정 사항입니다(RUN 명령은 Dockerfile 스크립트입니다).
RUN sed -i '/^deb http\:\/\/httpredir\.debian\.org\/debian jessie main$\|^deb http\:\/\/httpredir\.debian\.org\/debian jessie\-updates main$\|^deb http\:\/\/security\.debian\.org jessie\/updates main$/d' /etc/apt/sources.list
RUN echo -e 'deb http://httpredir.debian.org/debian stable main contrib non-free\ndeb-src http://httpredir.debian.org/debian stable main contrib non-free\ndeb http://httpredir.debian.org/debian jessie-backports main contrib non-free\ndeb-src http://httpredir.debian.org/debian jessie-backports main contrib non-free\ndeb http://httpredir.debian.org/debian jessie-updates main contrib non-free\ndeb-src http://httpredir.debian.org/debian jessie-updates main contrib non-free\ndeb http://security.debian.org jessie/updates main contrib non-free\ndeb-src http://security.debian.org jessie/updates main contrib non-free' >> /etc/apt/sources.list
제거 프로세스와 에코 프로세스를 분리한 이유는 기본적으로 sed가 설치되어 있지 않지만 에코가 있을 수 있는 또 다른 새로운 초경량 Linux 배포판과 함께 이 Dockerfile을 사용할 것이기 때문입니다. 이렇게 하면 해당 줄을 삭제할 수 없어도 수정 사항이 계속해서 반영됩니다.
여러 줄 솔루션의 문제점은 경량(단 하나의 Dockerfile만)으로 유지하고 외부 .sh 스크립트를 포함하고 싶지 않다는 것입니다.
답변1
sed 패턴은 끝에 고정되어 있지 않으므로 새 줄과 일치합니다. 또 다른 해결책은 행을 삭제하고 읽는 대신 행을 수정하는 것입니다.
먼저 너무 넓지 않게 하여 원본 스크립트를 더 읽기 쉽게 만들 수 있는지 살펴보겠습니다.
sed -i -r '/deb http\:\/\/httpredir\.debian\.org\/debian jessie main/d' /etc/apt/sources.list
sed -i -r '/deb http\:\/\/httpredir\.debian\.org\/debian jessie\-updates main/d' /etc/apt/sources.list
sed -i -r '/deb http\:\/\/security\.debian\.org jessie\/updates main/d' /etc/apt/sources.list
cat >> /etc/apt/sources.list << EOF
deb http://httpredir.debian.org/debian stable main contrib non-free
deb-src http://httpredir.debian.org/debian stable main contrib non-free
deb http://httpredir.debian.org/debian jessie-backports main contrib non-free
deb-src http://httpredir.debian.org/debian jessie-backports main contrib non-free
deb http://httpredir.debian.org/debian jessie-updates main contrib non-free
deb-src http://httpredir.debian.org/debian jessie-updates main contrib non-free
deb http://security.debian.org jessie/updates main contrib non-free
deb-src http://security.debian.org jessie/updates main contrib non-free
EOF
사실, 하나의 sed 명령으로 모든 작업을 수행하지 못할 이유가 없습니다.
sed /etc/apt/sources.list -i \
-e '\!deb http://httpredir\.debian\.org/debian jessie main$!d' \
-e '\!deb http://httpredir\.debian\.org/debian jessie-updates main$!d' \
-e '\!deb http://security\.debian\.org jessie/updates main$!d' \
-e '$a \
deb http://httpredir.debian.org/debian stable main contrib non-free\
deb-src http://httpredir.debian.org/debian stable main contrib non-free\
deb http://httpredir.debian.org/debian jessie-backports main contrib non-free\
deb-src http://httpredir.debian.org/debian jessie-backports main contrib non-free\
deb http://httpredir.debian.org/debian jessie-updates main contrib non-free\
deb-src http://httpredir.debian.org/debian jessie-updates main contrib non-free\
deb http://security.debian.org jessie/updates main contrib non-free\
deb-src http://security.debian.org jessie/updates main contrib non-free'
그럼 내가 한 일에 대해 이야기해보자. 첫 번째는 패턴 끝에 $를 추가하는 것입니다. 하지만 단일 sed 명령을 사용하면 경쟁 조건 창이 훨씬 더 좁아지고 sed가 완료될 때까지 원본 파일이 그대로 유지되므로 이 시점에서는 이것이 필요하지 않습니다. sed는 임시 파일을 원본 파일 위에 복사하며 이는 한 번만 발생합니다. 다음은 과잉 이스케이프를 줄이는 것입니다. 특히 - 및 :는 기본 또는 확장 정규 표현식의 특수 문자가 아니므로 이스케이프할 필요가 없습니다(그렇게 하면 공식적으로 POSIX에 따라 정의되지 않은 동작이 발생할 수 있지만 실제로는 거의 수행되지 않습니다). 이렇게 하면 이스케이프해야 할 슬래시가 많기 때문에 구분 기호를 ! 왜냐하면 \c 매칭 연산자를 사용하면 어디에도 사용되지 않기 때문입니다. 기본 정규식과 확장 정규식의 차이점에 대해 말하면 논란의 여지가 있는 연산자를 사용하지 않으므로 패턴이 어떤 방식으로 해석되는지는 중요하지 않으므로 -r 옵션을 제거해 보겠습니다. 이제 하나의 sed 호출에서 여러 sed 명령을 사용하므로 -e 옵션이 필요하며 각 sed 명령에 필요합니다. 이 경우 명령이 수정될 파일 앞에 올 필요가 없다는 추가 이점이 있습니다. a 명령으로 새 줄을 추가하여 끝내고 $로 제한하여 마지막 줄에서만 실행합니다. 이스케이프 처리하지 않으면 6자를 저장할 수 있습니다. 패턴이나 url이 긴 특성상 자기 자신도 일치하고 다른 것과도 일치할 가능성이 낮기 때문에 이 정도면 충분합니다.
또는 Perl 버전은 다음과 같습니다.
perl -pi \
-e 'next if m!deb http://httpredir\.debian\.org/debian jessie main$!;' \
-e 'next if m!deb http://httpredir\.debian\.org/debian jessie-updates main$!;' \
-e 'next if m!deb http://security\.debian\.org jessie/updates main$!;' \
-e 'END print "
deb http://httpredir.debian.org/debian stable main contrib non-free
deb-src http://httpredir.debian.org/debian stable main contrib non-free
deb http://httpredir.debian.org/debian jessie-backports main contrib non-free
deb-src http://httpredir.debian.org/debian jessie-backports main contrib non-free
deb http://httpredir.debian.org/debian jessie-updates main contrib non-free
deb-src http://httpredir.debian.org/debian jessie-updates main contrib non-free
deb http://security.debian.org jessie/updates main contrib non-free
deb-src http://security.debian.org jessie/updates main contrib non-free\n";}'
다음과 같을 수 있습니다.
perl -pie 'next if m!deb http://httpredir\.debian\.org/debian jessie main$!; next if m!deb http://httpredir\.debian\.org/debian jessie-updates main$!; next if m!deb http://security\.debian\.org jessie/updates main$!; END{ print "deb http://httpredir.debian.org/debian stable main contrib non-free\ndeb-src http://httpredir.debian.org/debian stable main contrib non-free\ndeb http://httpredir.debian.org/debian jessie-backports main contrib non-free\ndeb-src http://httpredir.debian.org/debian jessie-backports main contrib non-free\ndeb http://httpredir.debian.org/debian jessie-updates main contrib non-free\ndeb-src http://httpredir.debian.org/debian jessie-updates main contrib non-free\ndeb http://security.debian.org jessie/updates main contrib non-free\ndeb-src http://security.debian.org jessie/updates main contrib non-free\n";}'