Linux-stdin-stdout-stderr-2


stderr 는 버퍼를 사용하지 않지만 그것과 별개로 그대로 출력하기 때문에 grep 이 되지 않는것입니다.

https://www.facebook.com/groups/korelnxuser/permalink/2060620130779393/

소용환님께서 답변해주셔서 알 수 있었습니다.

그래서 테스트를 진행하였습니다.

stdbuf 명령어를 이용하여 buffer 를 제거하고 grep 해보았습니다. stdbuf -o0 는 stdout 를 unbuffered 로 출력하는 명력어 입니다.

# cat test.txt 
1
2
3
4
5
6
# stdbuf -o0 cat test.txt | grep 2
2

.

그런데 문득 버퍼사이즈가 0인것과 버퍼가 아주없는 unbuffered 는 차이가 있다는것을 알게되었습니다. 그래서 stderr 에 buffer 를 주었습니다.

# cat test.txt 1>&2 | stdbuf -eL grep 2
1
2
3
4
5
6

# stdbuf -eL cat test.txt 1>&2 | grep 2
1
2
3
4
5
6

.

grep 이 되지 않는것을 확인할수 있었습니다.

이 테스트를 결과로 stderr가 grep 되지 않는것은 buffer의 사용유무와 상관없이 그대로 출력하기 때문임을 알게되었습니다.

https://www.pixelbeat.org/programming/stdio_buffering/

이해를 돕기위해 pixelbeat.org 의 이미지를 첨부합니다.

Linux-stdin-stdout-stderr-1


잘못된 정보를 공유하였습니다.
그부분을 수정하고자 게시물을 다시 올립니다.

바로잡은 내용은 아래의 글입니다.

리눅스에서 stderr 으로 받는 문자열은 grep이 되지 않는다.

이유는 stderr는 Unbufferd 로 출력만 하기때문이다.

# httpd -T | grep http
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.0.10.6. Set the 'ServerName' directive globally to suppress this message
(98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
AH00015: Unable to open logs

.

위의 경우가 그 예이다.

우리가 사용하는 grep, awk 같은 명령어는 buffer를 이용한다. 그런데 stderr는 buffer 를 거치지 않고 출력하기때문에 grep 나 awk를 사용할수 없는 것이다.

이것을 이해하기 위해선 Buffering을 이해해야 한다.

이런 경우 우리는 2>&1 같은 리디렉션을 이용하여 처리를 한다.

2(stderr)>(리디렉션)&(실행한 다음)1(stdout) 이것은 표준에러를 표준출력으로 변경해준다는 의미로 받아들이면 접근이 굉장히 어렵다. 더 풀어써보겠다.

stderr 는 unbuffer 고 이것을 pipe buffer 를 거쳐 stdin 으로 들어가 grep 은 버퍼내의 데이터를 읽어들여서 stdout로 출력하게 되는것이다.

그냥 버퍼까지 올리지 않던 데이터를 리디렉션으로 버퍼에 넣어준다고 생각하자.

# httpd -T 2>&1 | grep http
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.0.10.6. Set the 'ServerName' directive globally to suppress this message

.

다음과 같이 grep 가 동작한다.

grep 는 버퍼를 사용하는 명령어다. 버퍼를 사용하지 않는 출력(stderr)은 grep 할수없다.

버퍼를 사용하는 출력(stdout)는 grep 할수있다.

Linux-one-line-Challenge

리눅서들은 이상한 것에 집착하곤 한다.

한줄 명령어가 그 중 하나이다.

보통 그렇다. 이런 아무렇지 않은 질문으로 시작한다.

질문은 곧 챌린지가 되고 도전이 시작된다.

적당히 조언했던것이..

다른 분의 참전으로 새로운 측면을 맞이한다.

ls -lt 는 시간순 정렬이다.

대충이라고 하셨지만 골자는 이렇다. ls -ptl 은 파일의 최신순서대로 정렬해서 보여준다. 거기에 / 디렉토리를 빼고 토탈을 빼는 방식이다.

물론 이런것들이 한방에 되진 않는다.

여러 가지 조언을했지만 사실 말처럼 쉽게 되지 않는다. 그저 제한사항 들을 확인하는 것이다.

위에 내가 쓴 명령어는 안됬다.

하얀색 프로필을쓰시는 분은 초굇수다.

이제 거의 정답이 나왔다. 여기서 디렉토리만 제외하면 정답이다.

맞다 나눠서 하는것도 정답이다. 하지만, 챌린지는 그렇게 쉽지 않다. 한줄로 해야한다.

find . -type d -exec bash -c 'echo "next dir: ${1}" ; ls -lt "$1" |
    grep ^- |
    head -n 5' bash {} \;

정답이다. 그러나 더깔끔하게 하고싶었다 나는...ㅠㅠ

find /root -type d -exec sh -c "ls -lpt {} | egrep -v '^d|합계' | head -n 1" \;

나는 grep -v 로 ^d 옵션을 줘서 첫글자가 d 그러니까 디렉토리 속성일경우 제외하여 결과를 만들었다.

sh -c "find /root -type d -exec bash -c \"ls -lpt {} | egrep -v '/|total' | head -n 1 \" \;" | awk '{print $9}'

리눅스는 각자의 방법이 있다.

그런 방법들이 너무 사랑스럽다.

오랜만에 즐거운 one line Challenge 였다.

좋은하루되시라!