I have a scale that continuously send data via serial port, 2 times per second. The only reliable way on reading this data happened to be cat command. The following works:

cat /dev/ttyUSB0

But the problem with cat is that, as it doesn't receive an EOF, it continues retrieving data. I've also tried head, read and tail.

head -1 /dev/ttyUSB0 | strings

works 'almost' everytime, but now and then shows old data, and only re-running cat command fixes it (?). The string after pipe retrieves only printable data.

read line < /dev/ttyUSB0 | echo $line

now and then retrieves data, but most of the time only shows an empty line.

tail -1 < /dev/ttyUSB0

just freezes, waiting for EOF, maybe?

My issue is that i need to write a bash script that can be called and "read" /dev/ttyUSB0 and retrieve data. I'm going to use head. But I'm wondering, as cat never fails, if there's a way to capture only one line of cat output and then stop it.

Note: the port configuration is 9600 baud, 1 start bit, 8 data bits, no parity, 2 stop bits. To set the port properly this is the command:

sudo stty -F /dev/ttyUSB0 9600 -parity cs8 cstopb
  • Did you try dd ? It might work (with suitable options). Jul 12 '17 at 16:38
  • Your head command may be getting slightly old data due to a buffer, and you are reading the top of it. When you tried tail, it was with other arguments. Try repeating the head command options with tail
    – ivanivan
    Jul 12 '17 at 16:44
  • Thank Basile, I'll investigate dd. Ivan, I agree with you. I've assumed that I'm reading some kind of buffer of stdout. ¿is there a way to reset it?. And don't understand why cat isn't affected with this buffer issue. Thank you. I've used head -10 /dev/ttyUSB0 | tail -1. But get the same result, erratic.
    – thejavo
    Jul 12 '17 at 17:31
  • Try prefixing a non-cat command with stdbuf -i 0 -o 0, i.e. stdbuf -i 0 -o 0 head -1 /dev/ttyUSB0 | strings.
    – agc
    Jul 12 '17 at 19:33

Your best bet is to place the tty in raw mode, and write a program that discards characters until it sees the start of a message, and then prints characters until it reaches the end of a message. With 'raw' added to the stty, fgetc() can be used on the tty to get a single character.

off the cuff psuedo:

char = fgetc(serial_port);
if char == START_CHARACTER {
    for (i=0;i<MESSAGE_LENGTH;i++){

It may also be possible to do this with sed and a raw tty, see this other question: https://stackoverflow.com/questions/20943025/how-can-i-get-sed-to-quit-after-the-first-matching-address-range

  • thanks you very much KJ4IPS!, i'll try not to "sound" rude, but I lack the vocabulary to "sound polite enough", so excuse me. But the answer you've wrote doesn't solve my problem. The scale already transmits data with 2Hz frequency. Inmediately after been turned on. Constantly. It never stops. So it's not possible to reach an end of message. On the other hand, I'm interested in solving this with pure bash.
    – thejavo
    Jul 14 '17 at 12:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.