0

I wrote a bash command to test grep from a changing line:

for i in $(seq 0 9); do echo -e -n "\r"$i;  sleep 0.1; done | grep 5

The result shows:

9


Update

The real problem is as follows:

mplayer shows and refreshes a single-line playing progress when playing a media file. A sample result is:

A:  17.2 (17.2) of 213.0 (03:33.0)  0.5%

And I'm trying to grep this playing progress and ingore other lines. I used this command:

mplayer xxx.mp3 | grep ^A:

The result does not contain the line expected.


Update 2
mplayer xxx.mp3 | od -xda

shows:

0002140    4a5b    410d    203a    2020    2e31    2033    3028    2e31
          [   J  \r   A   :               1   .   3       (   0   1   .
        133 112 015 101 072 040 040 040 061 056 063 040 050 060 061 056
0002160    2932    6f20    2066    3132    2e33    2030    3028    3a33
          2   )       o   f       2   1   3   .   0       (   0   3   :
        062 051 040 157 146 040 062 061 063 056 060 040 050 060 063 072
0002200    3333    302e    2029    3020    342e    2025    5b1b    0d4a
          3   3   .   0   )           0   .   4   %     033   [   J  \r
        063 063 056 060 051 040 040 060 056 064 045 040 033 133 112 015
0002220    3a41    2020    3120    352e    2820    3130    342e    2029
          A   :               1   .   5       (   0   1   .   4   )    
        101 072 040 040 040 061 056 065 040 050 060 061 056 064 051 040
0002240    666f    3220    3331    302e    2820    3330    333a    2e33
          o   f       2   1   3   .   0       (   0   3   :   3   3   .
        157 146 040 062 061 063 056 060 040 050 060 063 072 063 063 056

And

mplayer xxx.mp3 | tr '\r' '\n'

shows

A:   0.2 (00.1) of 213.0 (03:33.0)  0.3% 
A:   0.3 (00.3) of 213.0 (03:33.0)  0.3% 
A:   0.5 (00.5) of 213.0 (03:33.0)  0.4% 
A:   0.6 (00.6) of 213.0 (03:33.0)  0.4% 
A:   0.8 (00.8) of 213.0 (03:33.0)  0.4% 
A:   1.0 (01.0) of 213.0 (03:33.0)  0.4%

While,

mplayer xxx.mp3 | tr '\r' '\n' | grep ^A

shows empty result.

Any tip will be appreciated.

1 Answers1

1

It's your definition of "line" that's causing the problem here. The -n means that all the numbers are output on a single line, according the the definition used by grep (a series of characters, terminated by the \n character):

\r1\r2\r3\r4\r5\r6\r7\r8\r9

If you pipe the output through something like a hex dump, you can see what's happening:

$ for i in $(seq 0 9); do echo -e -n "\r"$i;  sleep 0.1; done | grep 5 | od -xcb
0000000    300d    310d    320d    330d    340d    350d    360d    370d
         \r   0  \r   1  \r   2  \r   3  \r   4  \r   5  \r   6  \r   7
        015 060 015 061 015 062 015 063 015 064 015 065 015 066 015 067
0000020    380d    390d    000a
         \r   8  \r   9  \n
        015 070 015 071 012
0000025

That single line containing all the carriage returns (and not newlines) will, when output, appear to be a single line with just the 9 on it. Removing the -n will result instead in:

$ for i in $(seq 0 9); do echo -e "\r"$i;  sleep 0.1; done | grep 5 | od -xcb
0000000    350d    000a
         \r   5  \n
        015 065 012
0000003

which would look like just the 5 was being output.


If you have a process that outputs "lines" separated by carriage returns rather than newlines, there's nothing to stop you changing them on the fly so as to be able to handle them as real lines:

$ echo -e "junk\rA: good 1\rjunk\rA: good 2\rjunk" | tr '\r' '\n'  | grep '^A'
A: good 1
A: good 2

Applying that back to your original question, it would be (with the sleep removed since it's irrelevant):

$ for i in $(seq 0 9); do echo -e -n "\r"$i; done | tr '\r' '\n' | grep 5
5

$ for i in $(seq 0 9); do echo -e -n "\r"$i; done | tr '\r' '\n' | grep 5 | od -xcb
0000000    0a35
          5  \n
        065 012
0000002
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Thanks. If I want to keep `echo -e -n "\r"$i"`, is it possible to grep from it? `echo -e "\r"$i` adds \n to the end and fails to display the digit change within just one line. – Jonny Young Jan 12 '15 at 06:09
  • I updated my description: I'm trying to grep the playing progress line of mplayer's output. – Jonny Young Jan 12 '15 at 06:20
  • @Jonny, see my update, it's just a matter of turning those pseudo-lines into real lines. – paxdiablo Jan 12 '15 at 06:35
  • This method works file for my test command. While it fails when applying to the original problem. Maybe mplayer's output use another refreshing technique instead of '\r'? – Jonny Young Jan 12 '15 at 07:09
  • @Jonny, you can just pipe the `mplayer` output through `od -xcb`, as I have for the test data, to see what the output format is. – paxdiablo Jan 12 '15 at 07:19
  • I update my question with more details. It seems that we almost solve it. – Jonny Young Jan 12 '15 at 08:11
  • @Jonny, you need to show the hex dump, as requested. Based on what's posted, it should work. The only reason it won't work is if the line doesn't start with the A. The hex dump is needed to figure it out. – paxdiablo Jan 12 '15 at 08:16
  • OK, I added the hex dump in the question description. – Jonny Young Jan 12 '15 at 08:36
  • @Jonny: that should work. The only tricky b it in there is the `ESC [ J` for clearing to end of line but since that occurs _before_ the CR, it should have no effect. Executing `echo -e '\e[J\rA: 1.3\e[J\rxxx\e[J\rA: x' | tr '\r' '\n' | grep ^A` works fine so it looks like there's some issue outside the info you've given us. – paxdiablo Jan 12 '15 at 08:50
  • thanks a lot. I have learned a lot from your answer. Maybe I should post a question with title: how to get the `mplayer`'s single-line playing progress info. – Jonny Young Jan 12 '15 at 09:03