출력을 리디렉션하면 때때로 빈 파일이 생성되는 이유는 무엇입니까? [복사]

출력을 리디렉션하면 때때로 빈 파일이 생성되는 이유는 무엇입니까? [복사]

쉘 파이프라인은 너무 강력해서 가끔 실망스럽습니다.

같은예를 들어 파이프

echo abc > file.txt
cat file.txt | sed 's/a/1/' > file.txt

빈 것을 주세요 file.txt. 쉘이 >먼저 호출될 수 있다는 것을 깨닫고 변경했습니다.

echo abc > file.txt
{cat file.txt | sed 's/a/1/'} > file.txt

또 다른 빈 파일이 나를 또 놀라게 했다 file.txt. 결국 효과가 있었던 추악한 접근 방식은 다음과 같습니다.

echo abc > file.txt
echo $(cat file.txt | sed 's/a/1') > file.txt

이렇게 하면 쉘이 먼저 서브쉘을 실행한 다음 리디렉션됩니다.

질문

, , ... 등을 sed제거할 수 있는 더 나은 방법을 알고 있지만 여기서 궁금한 점은 셸의 구문을 철저하게 배우는 것입니다.echocatgrep이 질문은 위의 특정 문제를 해결하는 방법에 관한 것이 아닙니다.

Q1 (편집자: 주제 외) 문법을 배울 때 사용할 수 있는 좋은 자료가 있나요?

쉘마다 구문이 다를 수 있으므로 걱정됩니다.

2분기쉘을 장황하게 만들고 명령을 실행할 때마다 쉘이 수행하는 작업을 정확히 볼 수 있습니까?

Q3(편집: 주제에서 벗어남) 모범 사례를 위한 다른 제안이 있습니까? 감사합니다!

답변1

고려하다3.1.1 쉘 동작, 특히 작업이 수행되는 순서는 다음과 같습니다.

  • 리디렉션 처리됨앞으로실제로 명령이 실행되지만
  • 확장은 리디렉션 전에 처리됩니다.

이는 의 경우 cat file > file출력 리디렉션(파일 잘림)이 cat빌드 전에 발생하고 cat이제 작업할 빈 파일이 있음을 의미합니다.

하지만 echo "$(cat file)" > file예상하셨듯이명령 대체쉘 확장, 이는 리디렉션 전에 발생합니다.

전형적인 조언은

cat file > tmpfile && mv tmpfile file

당신은 그것을 사용할 수 있습니다mktemp여기.

또는 moreutils패키지를 설치하고 사용하십시오.sponge

cat file | sponge file

사용 중인 특정 명령을 해결하려면 다음을 변경하십시오.

cat file.txt | sed 's/a/1/' > file.txt

(GNU sed로 가정)

sed -i 's/a/1/' file.txt

답변2

하지 말아야 할 일 중 하나를 성공적으로 찾았습니다. :-) 작업 중인 파일로 리디렉션하지 마세요!

A1: 셸 구문을 배우기 위한 좋은 리소스는 다음과 같습니다.Bash 스크립팅에 대한 절대 가이드, 국제해사기구

A2: Bash 스크립트의 경우 더 자세한 출력을 사용할 수 있지만 set +x"프롬프트에서 실행" 수준에서 동일한 결과를 얻는 방법을 모르겠습니다.

A3: [solved]검색어에 추가하세요. 이미 알고 있는 문제가 아니라 문제에 대한 해결책을 찾으십시오.

답변3

문제를 해결하는 한 가지 방법은 순차적 리디렉션, 확장, 하위 쉘 등이 어떤 일이 발생하는지 정확히 이해하여 이러한 오류가 발생하기 전에 잡을 수 있도록 하는 것입니다.

나는 이것을 권장하지 않습니다. 때로는 여전히 엉망이 되어 데이터가 손실될 수 있습니다.

즐겨아니요이 모든 것을 올바르게 유지하고 더 바보 방지 코드를 작성할 수 있는 능력을 믿으십시오. 우리는 모두 때때로 바보입니다.

그래서

cp file.txt file.txt.old
cat file.txt.old | sed 's/a/1/' > file.txt

이는 라인 1이 라인 2보다 먼저 발생한다는 점을 제외하면 이벤트 순서에 대한 의존성이 없기 때문에 더 간단합니다.

추가적인 이점으로,다른전혀 실행하지 말아야 할 때 이 스크립트를 실행하면 오류가 발생합니다.

이 접근 방식의 비용은 .old파일이 어디에나 있다는 것입니다. 필요한 날에 지불하면 기뻐할 프리미엄입니다. 접시는 매우 저렴합니다.

관련 정보