전체 파일 시스템에서 삭제하도록 sed가 있습니까?

전체 파일 시스템에서 삭제하도록 sed가 있습니까?

아직 진단되지 않은 응용 프로그램 오류로 인해 디스크가 가득 찬 서버가 수백 대 있습니다. 중복된 줄이 가득한 파일이 있습니다. 로그 파일이 아니라 변수 정의가 포함된 사용자 환경 파일입니다(그래서 파일을 그냥 삭제할 수는 없습니다).

잘못 추가된 줄을 확인하고 제거하는 간단한 명령을 작성 sed하고 파일의 로컬 복사본에서 테스트했습니다. 예상대로 작동합니다.

그러나 디스크가 가득 찬 서버에서 시도하면 대략 다음과 같은 오류가 발생합니다(복사하여 붙여넣기가 아닌 메모리에서 발생한 오류입니다).

sed: couldn't flush /path/to/file/sed8923ABC: No space left on deviceServerHostname

당연히 나는알다남은 공간이 없습니다. 그래서 물건을 삭제하려고 해요! ( sed제가 사용한 명령은 4000줄 이상의 파일을 약 90줄로 줄였습니다.)

sed명령은 단지sed -i '/myregex/d' /path/to/file/filename

디스크가 꽉 찼을 때 이 명령을 적용할 수 있는 방법이 있나요?

(빠른 수정으로 수백 대의 서버에 적용해야 하기 때문에 자동화해야 합니다.)

(당연히 애플리케이션 오류를 진단해야 하는데 그 사이 서버가 작동하지 않네요...)


고쳐 쓰다:삭제될 수 있는 다른 항목을 삭제하면 해결되는 상황이 있었지만 여전히 답변을 원합니다.이것질문, 이것은 미래와 다른 사람들에게 도움이 될 것입니다.

/tmp그것은 작동하지 않습니다. 동일한 파일 시스템에 있습니다.

디스크 공간을 확보하기 전에 테스트를 수행한 결과 파일을 열고 실행한 다음 를 사용하여 vi파일의 줄을 삭제할 수 있다는 것을 발견했습니다 . 별도의 파일 시스템에 의존하지 않고도 자동으로 이 작업을 수행하는 것이 가능할 것 같습니다. 임시파일을 보관해두세요.... ....(?):g/myregex/d:wq

답변1

-i옵션은 실제로 원본 파일을 덮어쓰지 않습니다. 출력으로 새 파일을 만든 다음 원래 파일 이름으로 이름을 바꿉니다. 파일 시스템에 이 새 파일을 위한 공간이 없기 때문에 실패합니다.

이 작업은 스크립트에서 직접 수행해야 하지만 다른 파일 시스템에 새 파일을 생성해야 합니다.

또는 정규식과 일치하는 줄을 삭제하는 경우 를 사용할 수 grep있습니다 sed.

grep -v 'myregex' /path/to/filename > /tmp/filename && mv /tmp/filename /path/to/filename

일반적으로 프로그램이 입력과 출력에 동일한 파일을 사용하는 것은 거의 불가능합니다. 일단 파일 쓰기를 시작하면 프로그램이 읽는 파일 부분에 더 이상 원본 내용이 표시되지 않습니다. 따라서 먼저 원본 파일을 어딘가에 복사하거나 새 파일을 작성하고 완료되면 이름을 바꿔야 합니다.

임시 파일을 사용하지 않으려면 파일 내용을 메모리에 캐시해 보세요.

file=$(< /path/to/filename)
echo "$file" | grep -v 'myregex' > /path/to/filename

답변2

그것이 sed작동하는 방식입니다. -i(내부 편집)과 함께 사용 하면 sed처리된 파일의 새 내용이 포함된 임시 파일이 생성됩니다. 완료되면 sed현재 작업 파일을 임시 파일로 바꿉니다. 유틸리티는 파일을 편집하지 않습니다.제자리에. 이것이 바로 모든 편집자가 하는 일입니다.

이는 셸에서 다음 작업을 수행한 것과 같습니다.

sed 'whatever' file >tmp_file
mv tmp_file file

이 시점에서 sed시스템 호출을 사용하여 버퍼링된 데이터를 오류 메시지에 언급된 파일로 플러시해 보십시오 fflush().

출력 스트림의 경우 fflush()스트림의 기본 쓰기 기능을 통해 지정된 출력 또는 업데이트 스트림에 대한 모든 사용자 공간 버퍼링 데이터를 강제로 씁니다.


귀하의 문제에 대한 해결책이 있습니다. 별도의 파일 시스템을 마운트하고( tmpfs예를 들어 메모리가 충분하거나 외부 저장 장치가 있는 경우) 일부 파일을 그곳으로 이동하고 처리한 다음 다시 이동합니다.

답변3

ex이 질문을 게시한 이후로 이것이 POSIX 호환 프로그램이라는 것을 알게 되었습니다 . 거의 보편적으로 심볼릭 링크되어 있지만 vim어느 쪽이든 다음은 (내 생각에) ex파일 시스템과 관련된 핵심 사항입니다(POSIX 사양에서 가져옴).

이 섹션에 사용된 용어버퍼 편집현재 작업 텍스트를 설명하세요. 이 용어는 특정 구현을 의미하지 않습니다. 모든 편집 변경 사항은 편집 버퍼에서 수행되며, 편집기 명령에 대한 변경 사항은 파일에 기록될 때까지 파일에 영향을 주지 않습니다.

"……영향을 미칠 것이다어느파일..." 파일 시스템에 무언가(임시 파일 포함)를 넣는 것은 "모든 파일에 영향을 미치는 것으로 간주됩니다. "아마도?*

열심히 공부했다POSIX 사양exex특정 명령이 산재되어 있는 온라인에서 발견되는 일반적인 스크립팅 사용 vim과 비교하여 이식 가능한 용도에 대한 몇 가지 "문제점"이 지적되었습니다 .

  1. +cmdPOSIX에 따르면 구현은 선택 사항입니다.
  2. 여러 -c옵션을 허용하는 것도 선택 사항입니다.
  3. 전역 명령은 :g이스케이프되지 않은 다음 줄 바꿈까지 모든 것을 "먹습니다"(따라서 끝에서 한 번이 아니라 정규식에 대해 찾은 각 일치 후에 실행됩니다). 그래서 -c 'g/regex/d | x'삭제만 할 수 있어요하나인스턴스를 만든 다음 파일을 종료합니다.

그래서 제가 조사한 바에 따르면,특정 정규식과 일치하는 모든 줄을 제거하기 위해 전체 파일 시스템에서 파일을 내부에서 편집하는 POSIX 호환 방법은 다음과 같습니다.

ex -sc 'g/myregex/d
x' /path/to/file/filename

파일을 버퍼에 로드할 만큼 충분한 메모리가 있는 경우 이 방법이 작동합니다.

*기타 주의사항을 발견하시면 댓글로 알려주세요.

답변4

다른 답변에서 언급했듯이 sed -i파일을 새 파일에 복사하여 작동합니다.같은 디렉토리에, 변경 작업을 수행한 다음 새 파일을 원본 파일 위로 이동합니다. 그것이 작동하지 않는 이유입니다.  (Original Line Editor)는 다소 유사하게 작동하지만 지난번 확인했을 때 임시 파일 ed용이었습니다 . 파일 시스템이 가득 찬 시스템과 다른 /tmp경우 이 작업을 수행할 수 있습니다./tmped

다음을 시도해 보십시오(대화형 쉘 프롬프트에서):

$ 편집/경로/대상/파일/파일 이름
G/정규식/디

( P이것은수도P) 꼭 필요한 것은 아닙니다. 프롬프트를 켜두지 않으면 어둠 속에서 작업하게 되어 일부 사람들은 이를 불편하게 생각합니다. 그리고 wq의식과그것.

ed신비한 진단으로 유명합니다. 언제든지 *프롬프트(예:) 이외의 내용이나 작업이 성공했음을 명확하게 확인하는 내용(예:특히?)가 포함된 경우원하지 않는다파일에 쓰기(사용됨 w) 그냥 포기 해 ( q). 그래도 마음이 풀리지 않으면 q다시 말해보세요.

/tmp디렉터리가 가득 찬 파일 시스템에 있는 경우 (또는 해당 파일 시스템도 가득 찬 경우) 어딘가에서 공간을 찾아보세요. Chaos에서는 tmpfs 또는 외부 저장 장치(예: 플래시 드라이브) 마운트에 대해 언급합니다. 그러나 파일 시스템이 여러 개 있고 그렇지 않은 경우모두완료되면 기존의 다른 것 중 하나를 간단히 사용할 수 있습니다. Chaos는 파일을 다른 파일 시스템에 복사하고 그곳에서 편집( 사용 sed)한 다음 다시 복사할 것을 권장합니다. 현 시점에서는 이것이 아마도 가장 간단한 해결책일 것입니다. 그러나 또 다른 접근 방식은 여유 공간이 있는 파일 시스템에 쓰기 가능한 디렉터리를 만들고 TMPDIR해당 디렉터리를 가리키도록 환경 변수를 설정한 다음 ed. 뭐든 해를 끼치세요.)

작업을 시작하면 ed다음을 수행하여 이를 자동화할 수 있습니다.

편집하다파일 이름<< 터미네이터
G/정규식/디
EOF

스크립트에서. 아니면 don_crissti의 제안을 따르세요.printf '%s\n' 'g/myregex/d' w q | ed -s filename

관련 정보