쉘 파이프라인은 너무 강력해서 가끔 실망스럽습니다.
예
같은예를 들어 파이프
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
제거할 수 있는 더 나은 방법을 알고 있지만 여기서 궁금한 점은 셸의 구문을 철저하게 배우는 것입니다.echo
cat
grep
이 질문은 위의 특정 문제를 해결하는 방법에 관한 것이 아닙니다.
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
파일이 어디에나 있다는 것입니다. 필요한 날에 지불하면 기뻐할 프리미엄입니다. 접시는 매우 저렴합니다.