[완료] bash read 의 한번의 읽는 양 조절

ssanighe의 이미지

안녕하세요.

while read line; do echo "${line}"; sleep 0.1; done < filename

read로 한번에 한 line 씩 읽게되는데요..
한번에 읽는 양을 byte 로 정해줄수 없을까요?

예를들어 한번에 256 만큼 읽어다오.. 이런거요..

wariua의 이미지

http://kldp.org/node/81492 에서 이어지는 질문이로군요 :-)

일단 "man bash"에서 read 명령에 대한 도움말을 보시면 아실 수 있듯 "-n" 옵션을 통해 읽어들이는 글자의 최대 개수를 지정할 수 있습니다. 그렇다면 이렇게 시도해 볼 수 있겠군요.

while read -n 256 chars; do echo "${chars}"; sleep 0.1; done < filename

근데 이렇게 하면 256글자가 넘는 행이 줄줄이 쪼개지는 문제가 발생합니다. 한편으로, 256글자 이하의 행은 한 줄씩 읽어들이면서 sleep을 합니다. (수십만 행의 로그 파일에서는 대략 무시무시한 일이죠.) 이건 결국 read가 개행문자를 만나면 읽기를 중단하는 문제 때문입니다.

그렇다면 이렇게 시도해 볼 수도 있습니다. 일단 delimiter라는 파일을 만들어서 다음과 같은 문자를 하나 덜렁 집어넣습니다.

%

단, 이 문자는 압축하려고 하시는 로그 파일에 내에는 존재하지 않는 문자여야 합니다. grep으로 찾아보시... 이런, 그러면 CPU 사용량이 올라가면서 경보가 울리겠군요 :-)

뭐, 여튼 집어넣은 다음에;; 다음과 같은 식으로 명령을 내려주시면 됩니다.

cat some.log delimiter | while read -d "%" -n 25600 chars; do echo -n "${chars}"; sleep 0.1; done

하지만 이렇게 해도 역시 개행문자 때문에 가끔씩 2개의 줄이 하나로 이어져서 출력되는 문제가 발생합니다. 뭔가... 개행문자에 대한 '특단의 조처'가 필요한 상황입니다.

개행문자까지도 아예 인코딩을 해버려서 read 명령이 손대지 못하도록 해버리면 어떨까요? 그래서 이메일이나 암호화 프로그램 등에서 종종 쓴다는 base64 인코딩을 이용해 봤습니다. 압축을 하는 명령까지 함께 추가했습니다.

uuencode -m some.log - | cat - delimiter | while read -d "%" -n 25600 chars; do echo -n "${chars}"; sleep 0.1; done | uudecode | gzip -c - > some.log.gz

(헥헥~) 이렇게 하니 제 PC에서 30%가 좀 넘는 CPU 사용량을 보이면서 40MB로 로그 파일을 압축하는데 6분이 걸리더군요...

근데 파이프를 줄줄이 이어붙여서인지 bash 프로세스가 CPU 사용량의 대부분을 차지합니다. 한편으로 -n 옵션의 값을 크게 하면 처리 속도는 빨라지지만 bash의 CPU 사용량이 팍팍 증가합니다. 또한 sleep 시간을 줄여도 bash의 CPU 사용량이 증가합니다.

bash 프로세스가 대부분의 CPU 시간을 차지하는 건 배보다 배꼽이 큰 상황이죠:-) 그리하여... 원래 글에서 익명사용자님께서 작성해 주신 프로그램을 이용하는 것을 추천합니다.

& 덕분에 재밌게 놀아봤습니다.

&& 정작 딱 떨어지는 솔루션은 제공해 드리지 못했군요:-) 그건 이후 나타나실 어느 쉘스크립트 구루님께서...;;
----
$PWD `date`

$PWD `date`

ssanighe의 이미지

답변 감사드립니다. 저도 -n 옵션을 써 봤으나.. 한 줄씩 읽는 원칙은 변하지 않더군요..

두 분다 치환을 전제로 솔루션을 제공해 주셨군요.
본래 간단히 하려고 bash shell 로 하는 방법을 물어봤으나..
아무래로 전에 익명 사용자님이 작성해 주신 방법대로
c 코드를 이용하는 편이 나을 것 같아요.

애써 주신거 너무 너무 감사합니다.

bushi의 이미지

짜깁기.

IFS=
cat "$1" | \
tr '\n' '\033' | \
while read -r -n 16; \
do \
    echo -n ${REPLY}; \
    sleep 0.1; \
done | \
tr '\033' '\n' | \
gzip -9 -c - > $(basename "$1").gz

테스트를 C 소스로 하다보니 tab 문자가 걸려서 IFS 를 없애버렸습니다.
때문에... 스크립트 파일 형태로 밖에 못 쓰겠군요.

역시 C 소스로 테스트 하다보니 \ 가 걸려서 read 옵션에 -r 추가.

\n 을 ESC 로 바꿔치기...
간단히 하려고 tr 을 사용했는데 perl 이나 sed 사용하면 완벽한 ESC sequence 를 만들어서 치환할 수 있을 것으로 예상됩니다.
예를 들어

perl -pe "s|\012|\033_I_AM_LF|g"
perl -pe "s|\033_I_AM_LF|\012|g"

뭐 이렇게...
어쨌든 지금은 ESC 하나만 사용하므로 원본 문서가 ESC sequence 로 예쁘게 꾸며진 문서라면 g.g.

보시다시피 블록사이즈는 16자로 했는데,
버그가 있습니다.
맨 마지막블록을 항상 잃어버리는군요.

버그 사냥은 ... 직접 해보심이...
kldp 가 code complete 을 해주는 곳이 아니잖아요 ?

ai의 이미지

newline 상관없이 일정한 바이트만큼 읽어오려면 이런 방법도 있습니다.
첫번째 라인 만큼은 한 라인 전체를 읽어오게 됩니다만..

$ cat logfile | perl -ne '$/=\65535; print STDOUT $_; print STDERR `date`; sleep 1;' | bzip2 --fast > log.bz2

--
War doesnt determine whos right, just whos left.

War doesnt determine whos right, just whos left.

ssanighe의 이미지

환상적이군요!ㅋ

근데 중간에 date는 별 의미없이 찍는거죠?
흠.. 그리고 perl 구분에는 sleep 말고 usleep 은 없나요?

1초는 너무 길어요 =_=

pung96의 이미지

Quote:

첫번째 라인 만큼은 한 라인 전체를 읽어오게 됩니다만..

BEGIN 블럭을 써도 안될까요?

jg의 이미지

$ cat test2.txt | while x=`dd ibs=10 count=1 2>/dev/null` && test x"$x" != x ;do echo $x; sleep 1; done

$Myoungjin_JEON=@@=qw^rekcaH lreP rehtonA tsuJ^;$|++;{$i=$like=pop@@;unshift@@,$i;$~=18-length$i;print"\r[","~"x abs,(scalar reverse$i),"~"x($~-abs),"]"and select$good,$day,$mate,1/$~for 0..$~,-$~+1..-1;redo}

ssanighe의 이미지

감사합니다.

근데, newline이 모조리 사라지네요..

jg의 이미지

$ cat test2.txt | while x=`dd ibs=10 count=1 2>/dev/null` && test x"$x" != x ;do echo "$x"; sleep 1; done

echo에서 따옴표가 빠졌군요.

$Myoungjin_JEON=@@=qw^rekcaH lreP rehtonA tsuJ^;$|++;{$i=$like=pop@@;unshift@@,$i;$~=18-length$i;print"\r[","~"x abs,(scalar reverse$i),"~"x($~-abs),"]"and select$good,$day,$mate,1/$~for 0..$~,-$~+1..-1;redo}

ssanighe의 이미지

헛, echo 에 따옴표 차이가 이런 것이였군요~

근데 이번엔 10byte 마다 newline 이 생기네요..

jg의 이미지

echo -n "$x"

$Myoungjin_JEON=@@=qw^rekcaH lreP rehtonA tsuJ^;$|++;{$i=$like=pop@@;unshift@@,$i;$~=18-length$i;print"\r[","~"x abs,(scalar reverse$i),"~"x($~-abs),"]"and select$good,$day,$mate,1/$~for 0..$~,-$~+1..-1;redo}

jg의 이미지

echo -n "$x"

이제 된 것 같군요.
쓰레드 닫았으면 좋겠습니다.

$Myoungjin_JEON=@@=qw^rekcaH lreP rehtonA tsuJ^;$|++;{$i=$like=pop@@;unshift@@,$i;$~=18-length$i;print"\r[","~"x abs,(scalar reverse$i),"~"x($~-abs),"]"and select$good,$day,$mate,1/$~for 0..$~,-$~+1..-1;redo}

ssanighe의 이미지

문제가 완벽하게 해결이 되었네요.
이번, 저번 쓰레드를 통해서 shell script와 많이 친해졌습니다.
하하.

다시한번 감사드립니다.

ssanighe의 이미지

.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.