1년 전 나는Linode에 NixOS를 설치하는 방법에 대한 튜토리얼.
설치 미디어에 iso 파일을 배치하는 것과 관련된 대부분의 튜토리얼에서는 항상 다음을 사용하는 것 같습니다 dd
."dd가 지금도 말이 되나요?"그는 내 질문에 대답하지 않았습니다. 또한 원래 이 튜토리얼에서 사용되었으며 다음과 같이 dd
소스에서 ISO를 파이핑하는 동안 sha256 체크섬을 사용하여 iso를 확인하도록 약간 수정했습니다 .tee
curl -L $iso | tee >(dd of=/dev/sda) | sha256sum
그러나 제 생각에는 dd
이것은 약간 중복되고 실제로 다음보다 훨씬 느립니다.
curl -L $iso | tee /dev/sda | sha256sum
몇 달 전 누군가가 튜토리얼을 따라하는 것을 도우면서 더 간단한 방법을 사용하는 데 문제가 있다는 것을 기억했습니다. 하지만 지난 주말에 두 번의 별도 설치를 시도했을 때 제대로 작동하는 것처럼 보였고 속도도 매우 빨랐습니다.
이 수정 사항은 튜토리얼을 업데이트하기 위해 끌어오기 요청을 제출할 만큼 충분히 안정적입니까?
아니면 운이 좋아서 작동하게 만들었고 dd
설치 미디어를 만드는 데 실제로 더 안전하고 신뢰할 수 있으므로 튜토리얼을 그대로 두어야 합니까?
답변1
사용하는 것이 dd
더 안전하거나 빠르거나 신뢰성이 떨어지는 것은 아닙니다 . 실제로 여기에는 두 가지 추가 실패 위험이 도입되었습니다. 사람들이 지침을 수동으로 따르면 두 위험 모두 실제로 문제가 될 가능성이 낮지만 지침이 자동화된 스크립트에 있는 경우 두 위험 모두 심각한 오류가 됩니다.
버그: 경쟁 조건
관찰하다:
bash-5.0$ echo hello | tee >(sleep 1; echo done); echo next step
hello
next step
bash-5.0$ done
Bash에서 출력 프로세스 대체는 비동기식입니다. 명령에 프로세스 대체가 포함된 경우 >(…)
프로세스 대체가 완료될 때까지 기다리지 않습니다.
… | tee >(dd of=/dev/sda) | sha256sum
따라서 다시 돌아올 때 dd
. 이는 사람이 반응하여 다른 명령을 입력할 만큼 오래 지속될 가능성은 없지만 다른 명령을 실행하는 스크립트 (예: eject
또는 그 이후)를 중단시킬 수 있습니다.mount
버그: 누락된 오류 감지
모든 것이 잘 작동하는 명목상의 사례부터 시작해 보겠습니다.
bash-5.0$ head -c 1m </dev/zero | tee >(cat >/dev/null) | wc -c; echo $?
1048576
0
이제 데이터 쓰기 명령이 실패하면 어떤 일이 발생하는지 살펴보겠습니다.
bash-5.0$ head -c 1m </dev/zero | tee >(false) | wc -c; echo $?
8192
0
파이프의 종료 상태는 오른쪽에만 의존하기 때문에 명령은 성공 상태를 갖습니다. 데이터 생성기가 데이터 프로세서에 연결된 경우 오류를 감지하는 것이 데이터 프로세서의 역할이라는 개념입니다. 불행하게도 이는 데이터 형식이 데이터 프로세서가 오류를 감지할 수 있는 경우에만 작동하지만 일반적으로 그렇지 않습니다. 특히 여기에서는 그렇지 않습니다.
tee
연결된 파이프에 쓸 수 없으면 완전히 포기하게 됩니다 false
. 데이터를 읽은 적이 없으므로 을(를 false
) 통과하는 유일한 데이터 wc -c
는 2개입니다 PIPE_BUF
(하나는 tee
두 파이프 모두에 쓰고, 다른 하나는 tee
파이프에 쓰기 wc
만 하고 파이프에 쓰지 못함 false
). 파이프에 기록하고 데이터를 소비하는 false
것과 종료하는 상대적인 타이밍 에 따라 패스가 1개 또는 0개만 있을 수 있습니다 .tee
wc
PIPE_BUF
tee
이 옵션을 설정하면 오류를 감지할 수 있습니다 pipefail
. (이 가능성은 ksh, bash 및 zsh에 존재하지만 일반 sh에는 존재하지 않습니다.)
bash-5.0$ set -o pipefail; head -c 1m </dev/zero | tee >(false) | wc -c; echo $?
8192
141
tee
파이프는 쓸 수 없으므로 쉘 상태 128 + SIGPIPE 값(Linux의 경우 13)에 해당하는 SIGPIPE로 종료됩니다. 이 옵션으로 인해 pipefail
전체 파이프라인이 동일한 상태로 종료됩니다.
파이프는 프로세스 대체의 명령 실패를 tee
직접적으로 반영하는 것이 아니라 명령 실패를 반영합니다. 대체 프로세스의 명령이 모든 데이터를 성공적으로 읽었지만 성공적으로 처리하지 못한 경우 오류가 감지되지 않습니다.
bash-5.0$ head -c 1m </dev/zero | tee >(cat >/dev/null; false) | wc -c; echo $?
1048576
0
wc -c
모든 데이터가 처리되었습니다. cat >/dev/null; false
시뮬레이션이 모든 입력 명령을 올바르게 처리하지 못했습니다. 그럼에도 불구하고 명령 상태는 성공을 나타냅니다.
실제 예에서 이는 데이터 끝에 오류가 있는 경우(예: 대상 장치가 이미지보다 훨씬 작기 때문에) 이 오류가 감지되지 않음을 의미합니다( 의 오류 메시지를 통해서는 제외 dd
).
간단하고 올바른 솔루션
set -o pipefail
curl -L $iso | tee /dev/sda | sha256sum
또는 틀림없이 더 간단합니다.
curl -L $iso | tee >/dev/sda >(sha256sum)
그렇지 않은 경우 pipefail
두 번째 명령은 curl
실패하더라도 성공합니다. 그러나 이 실패는 확실히 잘못된 체크섬을 초래합니다.
dd 사용에 대한 일반 참고 사항
설치 미디어에 iso 파일을 넣는 방법을 다루는 대부분의 튜토리얼은 항상 dd를 사용하는 것 같습니다. 이것이 바로 "dd가 지금도 관련이 있습니까?"라는 질문에 대한 답변이 아닌 이유입니다.
글쎄, 어느 정도 그렇습니다. 구체적으로 그것은 어떤 목적이 있는지에 대한 질문에 대답합니다 dd
. dd
이 특정 접근 방식을 사용할 때 발생하는 특정 문제는 다루지 않습니다 .이 시간실제로 그 자체 때문은 아닙니다 dd
.
대부분의 튜토리얼에서 이를 사용하는 이유 dd
는 대부분의 튜토리얼이 이를 사용하기 때문입니다 dd
. 사람들은 dd
그것이 실제로 왜 사용되는지 이해하지 못하더라도 다른 곳에서 사용되는 것을 보았기 때문에 그것을 사용합니다 . 그 구문은 다른 명령과 다르기 때문에 다소 신비롭고 강력합니다. 하지만 지금은 dd of=/dev/sda
모든 힘이 있지만 /dev/sda
아무 것도 없습니다 dd
. 그것은 단지 가식적이고 허약한 글쓰기 방식일 뿐입니다 cat >/dev/sda
.