2>&1을 사용하여 stdout/stderr를 BASH 스크립트의 여러 명령 중 하나의 명령에만 지정하세요.

2>&1을 사용하여 stdout/stderr를 BASH 스크립트의 여러 명령 중 하나의 명령에만 지정하세요.

처음 올리는 글이니 양해 부탁드립니다 :)

저는 첫 번째 BASH 스크립트를 작성하고 systemd를 사용하여 타이머에서 이를 호출합니다(첫 번째 systemd 장치이기도 합니다!). 스크립트는 매일 백업을 실행하고 알림 전송을 사용하여 내 데스크탑에 알림을 보냅니다.

일부 추가 로깅을 Journalctl에 지시하고 싶지만 일부 특정 단일 명령에 대해서만 가능합니다. 나는 2>&1을 사용했다:

df -h | grep --color=never /mnt/Backups 2>&1

하지만 이렇게 하면 알림을 통해 전송된 데스크톱 알림에 백업 성공 여부에 관계없이 "성공"이라고 표시됩니다(systemd는 정상적으로 완료됩니다). 2>&1 및 알림 보내기를 제거하면 스크립트의 Borg 작업 부분에 대한 올바른 알림 제안이 제공되는지 테스트했습니다(성공 및 실패 모두 테스트).

그렇다면 어떻게 리디렉션을 시작하고 중지하고, 이를 Journalctl에 표시하고, 내 알림을 정확하게 표시합니까?

이것은 내 스크립트의 일부입니다.

df -h | grep --color=never /mnt/Backups 2>&1

SUCCESS=$?
echo $SUCCESS

## Use DESTOP Notifications.
if [ "${SUCCESS}" = "0" ]; then
notify-send -a Borg 'Operation was successful!' '~/.local/bin/borg-backup.sh' -u normal -i checkbox-checked-symbolic
else
notify-send -a Borg 'Operation was *NOT* successful' '~/.local/bin/borg-backup.sh' -u critical -i dialog-error
exit 1
fi 

감사해요:)

답변1

먼저, grep의 출력이 stderr로 전송되기를 원한다고 가정합니다. 2>&1은 stderr를 stdout으로 리디렉션합니다. 1>&2를 grep해야 할 수도 있습니다.

둘째, 리디렉션은 해당 단일 명령에 대해서만 작동합니다. 지속되지 않으므로 리디렉션을 시작하고 중지하는 것은 문제가 되지 않습니다.

셋째, 나는 "성공"을 얻지 못합니다(systemd는 그것을 잘 수행합니다). 테스트한 것은 df -h의 출력에 /mnt/Backups가 언급되어 있다는 것뿐입니다. 몇 가지 다른 요인으로 인해 프로세스가 중단될 수 있습니다.

넷째, 파이프라인의 프로세스 상태가 예상치 못한 경우가 있습니다. 각 프로세스의 상태는 PIPESTATUS 배열에 기록됩니다. 전체 파이프라인의 상태는 복잡합니다. 특히 리디렉션이 포함된 파이프는 하위 셸에서 실행될 수 있습니다(따라서 기본 셸은 스트림을 그대로 유지합니다). 이 경우, 나는 여러분의 성공이 파이프라인의 마지막 명령이 아니라 서브셸 자체의 종료 상태와 관련이 있다고 믿을 준비가 되어 있습니다.

나는 그것을 직접 사용할 만큼 충분히 신뢰하지 않기 때문에 이 물건에 대해 모호합니다. 내 생각은 다음과 같이 상태가 아닌 텍스트를 확인하는 것입니다.

MOUNT="$( df -h | grep --color=never /mnt/Backups )"
echo 1>&2 "Mount test gets ${MOUNT:-Nothing}"

if [[ "${MOUNT}" = "/mnt/Backups" ]]; then ...

이런 것들은 진단하기 어렵습니다. 저는 RC=$?명령 상태 저장, echo $?명령 상태 표시, declare -p PIPESTATUS상태 배열 표시 및 RP="$( declare -p PIPESTATUS )"상태 배열 저장을 사용하는 방법을 배우고 있습니다.

문제는 이 네 가지(변수에 대한 할당 포함) 모두 명령이며 상태가 0으로 재설정된다는 것입니다. 따라서 여러 채널을 통해 초기 명령 상태를 볼 수 없습니다. 상태는 일시적이지만 데이터는 영원합니다.

가장 좋은 메커니즘은 grep 개수를 일치시키고 grep -c반환된 개수를 변수에 저장하는 것입니다. grep이 표준 입력을 읽는 경우 이름을 출력하지 않으므로 파일 이름을 버릴 필요가 없습니다.

대용량 파일에 대한 개선 사항으로 grep -l첫 번째 일치 항목이 발견되면 종료하려면 .를 사용하세요( grep -c끝까지 계속 계산해야 함). grep -l테스트가 "", 또는 에 대해 수행되도록 일치 항목이 포함된 파일 이름을 출력합니다 "(standard input)".

관련 정보