8

I'm trying to get the output from ls /dev to match 'tty' that ends with numbers between 1-4.

So from:

tty5
tty4
tty2
tty6
tty1

Should match:

tty4
tty2
tty1

The regexp

"\s([tty]+[0-4])\s"

works in RegExr.

I've tried using this with grep:

ls /dev | grep -E \s([tty]+[0-4])\s

ls /dev | grep -E \s([tty]\+\[0-4])\s

ls /dev | grep -Ex \s([tty]+[0-4])\s

ls /dev | grep -P \s([tty]+[0-4])\s

as I've read in other posts, still I can't make it work.

  • 2
    When do grep and regex work as you expect? – OldBunny2800 Jan 21 at 0:52
31

The reason it isn't matching is because you are looking for whitespace (\s) before the string tty and at the end of your match. That never happens here since ls will print one entry per line. Note that ls is not the same as ls | command. When the output of ls is piped, that activates the -1 option causing ls to only print one entry per line. It will work as expected if you just remove those \s:

ls /dev | grep -E '([tty]+[0-4])'

However, that will also match all sorts of things you don't want. That regex isn't what you need at all. The [ ] make a character class. The expression [tty]+ is equivalent to [ty]+ and will match one or more t or y. This means it will match t,or tttttttttttttttt, or tytytytytytytytytyt or any other combination of one or both of those letters. Also, the parentheses are pointless here, they make a capture group but you're not using it. What you want is this:

$ ls /dev | grep '^tty[0-4]$'
tty0
tty1
tty2
tty3
tty4

Note how I added the $ there. That's so the expression only matches tty and then one number, one of 1, 2, 3 or 4 until the end of the line ($).

Of course, the safe way of doing this that avoids all of the dangers of parsing ls is to use globs instead:

$ ls /dev/tty[0-4]
/dev/tty0  /dev/tty1  /dev/tty2  /dev/tty3  /dev/tty4

or just

$ echo /dev/tty[0-4]
/dev/tty0 /dev/tty1 /dev/tty2 /dev/tty3 /dev/tty4
  • 1
    Great answer. Out of curiosity, in your regex solution (before you get into why you should use globbing instead -- which you totally should!), why not start the regex with ^? – JakeRobb Jan 20 at 18:09
  • 1
    @jakerobb um, because I didn't think to do it! I should have though, you're quite right. Thanks :) – terdon Jan 20 at 19:58
  • 2
    also /dev/tty{1..4} :) – Eevee Jan 20 at 20:34
  • 1
    @Eevee that depends on the shell you're using. – reinierpost Jan 21 at 10:15
  • 1
    @Eevee yes, not only is that not portable, it also prints error messages if any of those don't exist (with ls) and will print everything regardless of whether it exists with echo. – terdon Jan 21 at 10:17
7

That regex seems a little overcomplicated. Also, you should be using quoting!

$ ls /dev | grep -E "tty[1-4]$"
tty1
tty2
tty3
tty4

However, you should definitly read this: Why *not* parse `ls` (and what to do instead)?

  • That's great thanks, I'm still curious why it works in Regexr and not in grep -P, yeah forgot to write quotations in the post, I use them. Thanks I will have a look at that link. – Surister Jan 20 at 9:55
  • 2
    Most regex engines are a little bit different from each other. Even regexr has support for "Javascript" and "PCRE" variants in the top right menu. Also grep supports two different variants through grep and grep -E (which is same as egrep). All of these four are different to some extent. grep -P is the same as PCRE though. – Jonas Berlin Jan 20 at 10:38
  • 1
    I'd advise single quotes instead of double quotes in this answer. – reinierpost Jan 21 at 10:15
-1
bash-4.2$ ls -l /dev | grep -o "tty[1-4]$"
tty1
tty2
tty3
tty4


bash-4.2$ ls -l /dev | awk '/tty[1-4]$/{print $NF}'
tty1
tty2
tty3
tty4

bash-4.2$ output=$(ls /dev); echo "${output}" | grep "tty[1-4]$"
tty1
tty2
tty3
tty4
  • 9
    Why use -l? That just makes it more complicated (forcing you to use the non-standard -o and print $NF instead of print) for no benefit. And why would you store it in a variable to then print the same variable again? – terdon Jan 20 at 10:09

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.