현재 다음과 같이 로그 파일에 메시지를 기록하는 쉘 스크립트가 있습니다.
log_file="/some/dir/log_file.log"
echo "some text" >> $log_file
do_some_command
echo "more text" >> $log_file
do_other_command
이 스크립트를 실행하면 화면에 아무런 출력도 나오지 않고, 퍼티를 통해 서버에 연결되어 있기 때문에 스크립트 실행을 종료할 수 없고 원하기 때문에 다른 연결을 열어서 "tail -f log_file_path.log"를 해야 합니다. 실시간으로 출력을 볼 수 있습니다.
분명히 내가 원하는 것은 텍스트 메시지를 화면과 파일에 인쇄하는 것이지만 두 줄이 아닌 한 줄로 수행하고 싶습니다. 그 중 하나는 파일로 리디렉션되지 않습니다.
이 목표를 달성하는 방법은 무엇입니까?
답변1
이것은 작동합니다:
command | tee -a "$log_file"
tee
입력을 파일에 저장하고( -a
덮어쓰기 대신 추가 사용) 입력을 표준 출력에 복사합니다.
명령은 현재 비대화형으로 실행 중임을 감지할 수 있으므로 동작이 변경될 수 있습니다. 가장 일반적인 부작용은 색상 출력이 비활성화된다는 것입니다. 이런 일이 발생하면(ANSI 색상으로 구분된 출력을 원하는 경우) 명령 문서를 확인하여 강제로 대화형 동작으로 되돌릴 수 있는 방법이 있는지 확인해야 합니다 grep --color=always
.반품less --RAW-CONTROL-CHARS "$log_file"
이스케이프 코드 리터럴을 방해하지 않고 읽는 데 사용해야 하는 이스케이프 코드가 포함되어 있습니다 . 또한 로그 파일 내용을 만들 수 있는 방법이 없습니다.다른위 명령을 실행할 때 화면에 인쇄되는 내용은 무엇입니까? 따라서 화면에 색상으로 구분된 출력과 로그 파일에 색상이 아닌 출력을 가질 수 없습니다.
답변2
여기 및 의 문서를 사용하여 효율적이고 POSIX 친화적인 범용 수집기 모델에 사용할 수 있습니다.
. 8<<-\IOHERE /proc/self/fd/8
command
…
fn() { declaration ; } <<WHATEVER
# though a nested heredoc might be finicky
# about stdin depending on shell
WHATEVER
cat -u ./stdout | ./works.as >> expect.ed
IOHERE
heredoc를 열 때 IOHERE 입력 플래그를 사용하여 제한 플래그의 다른 쪽 끝을 만날 때까지 입력을 지정한 파일 설명자로 리디렉션해야 한다는 신호를 셸에 보냅니다. 주위를 둘러보았지만 heredoc 연산자와 함께 위에 보여드린 것처럼 리디렉션된 fd 번호를 사용하는 예는 많지 않습니다. 비록 그 사용이 POSIX 기본 셸 명령 가이드에 명확하게 지정되어 있지만 말이죠. 대부분의 사람들은 그냥 stdin을 가리키고 쏘지만, 나는 이런 방식으로 스크립틀릿을 얻으면 stdin이 자유롭게 유지되고 구성 응용 프로그램이 I/O 경로 차단에 대해 불평하지 않는다는 것을 발견했습니다.
Heredoc의 내용은 사용자가 지정한 파일 설명자로 스트리밍되며, 이는 쉘 코드로 해석되어 . . /proc/self 경로에 문제가 있으면 /dev/fd/n 또는 /proc/$$를 시도해 보십시오. 그런데 동일한 접근 방식이 파이프에도 적용됩니다.
cat ./*.sh | . /dev/stdin
아마도 적어도 보이는 것만큼 경솔한 행동일 것입니다. 물론 sh 를 사용하여 동일한 작업을 수행할 수 있지만 . .
어쨌든, 아시다시피 저는 아직 귀하의 질문에 답변하지 않았습니다. 그러나 생각해 보면 heredoc이 모든 코드를 .로 스트리밍하는 것처럼 단일하고 쉬운 종료 지점도 제공합니다.
. 5<<EOIN /dev/fd/5 |\
tee -a ./log.file | cat -u >$(tty)
script
…
more script
EOIN
따라서 heredoc에서 실행되는 모든 코드의 모든 터미널 표준 출력은 . 현재 stdout 방향을 모르기 때문에 버퍼링되지 않은 cat 호출을 포함시켰지만, 중복될 수 있고(거의 확실히 작성된 대로임) 파이프가 티에서 끝날 수 있습니다.
두 번째 예에서 누락된 백슬래시 따옴표에 대해 의문을 제기할 수도 있습니다. 시작하기 전에 이 섹션을 이해하는 것이 중요하며 이를 사용하는 방법에 대한 몇 가지 아이디어를 얻을 수 있습니다. 인용된 heredoc 제한자(지금까지 우리는 IOHERE 및 EOIN을 사용했습니다. 처음으로 백슬래시로 인용했지만 "단일" 또는 "큰" 따옴표도 같은 목적에 사용됩니다)는 쉘이 내용을 쓰는 것을 허용하지 않습니다. 따옴표가 없는 한정자는 확장을 위해 내용을 열어 둡니다. 이로 인해 구분 기호가 . 출처는 드라마틱합니다.
. 3<<HD ${fdpath}/3
: \${vars=$(printf '${var%s=$((%s*2))},' `seq 1 100`)}
HD
echo $vars
> 4,8,12…
echo $var1 $var51
> 4 104
구분 기호 제한자를 인용하지 않기 때문에 쉘은 결과 파일 설명자를 . 이로 인해 본질적으로 명령이 두 번 구문 분석됩니다. 이는 어쨌든 확장 가능합니다. $vars 매개변수 확장을 백슬래시했기 때문에 쉘은 첫 번째 패스에서 해당 선언을 무시하고 백슬래시만 제거했습니다. 따라서 전체 printf 확장 내용은 첫 번째 패스에서 null로 평가될 수 있었습니다. 스크립트는 두 번째 패스에서 획득되었습니다.
이 기능은 기본적으로 위험한 eval 쉘 내장 함수가 제공할 수 있는 것과 정확히 같습니다. 비록 구분된 문서에서 인용하는 것이 eval에서보다 처리하기 쉽고 위험하기는 하지만 말입니다. 신중하게 계획하지 않는 한 습관적으로 "EOF" 리미터를 참조하는 것이 가장 좋습니다. 그냥 말하는 거야.
편집: 글쎄, 나는 이것을 되돌아보고 그것이 약간 과했다고 생각합니다. 여러 출력을 단일 파이프에 연결하기만 하면 가장 쉬운 방법은 다음을 사용하는 것입니다.
{ or ( command ) list ; } | tee -a ea.sy >>pea.sy
중괄호는 현재 셸에서 무언가를 실행하려고 시도하며 중괄호는 자동으로 분리됩니다. 그럼에도 불구하고 누구나 말할 수 있듯이, 적어도 내 생각에는 .Heredoc 솔루션이 더 가치 있는 정보입니다. 특히 쉘이 실제로 어떻게 작동하는지 이해하려는 경우에는 더욱 그렇습니다.
재미있게 보내세요!
답변3
tee 문을 사용하여 실행하지 않으려면 다음을 수행하세요.
#!/bin/bash
# A Shell subroutine to echo to screen and a log file
log_file_name="/some/dir/log_file.log"
echolog()
(
echo "$@"
echo "$@" >> $log_file_name
)
echo "no need to log this"
echolog "some important text that needs logging"
이제 원래 스크립트에서 "echo"를 로그 파일에 출력하려는 "echolog"로 변경할 수 있습니다.
답변4
저는 Macos에서 사용하고 있습니다. Linux 시스템에서도 작동할 것입니다.
command > /dev/stdin > mylog.log