sh and grep numbers only

12,570

Solution 1

Something like this should work for you:

ls /a | egrep "^[0-9]"

Per @Anthons feedback egrep is deprecated, so you can use -E as a switch to the normal grep command instead:

ls /a | grep -E "^[0-9]"

Per @Stephane's feedback the extended regular expressions (ERE's) aren't even necessary in this situation. Really what matters is the quoting of the ^[0-9] to protect it from being interpreted by whatever version of /bin/sh you're using that's having the issue. So something like this would be the simplest fix to your issue:

ls /a | grep "^[0-9]"

-or-

ls /a | grep '^[0-9]'

Solution 2

By sh, I think you're refering to the Bourne shell which was the shell of most Unix systems before the mid 90s and was /bin/sh on Solaris prior to Solaris 11.

On Solaris 10 and older, don't use /bin/sh. That shell is from another era. Use /usr/xpg4/bin/sh instead.

In the Bourne shell ^ is an alias for | for compatibility with its predecessor the Thompson shell. So your command is like:

ls /a|grep |[0-9]

And the Bourne shell reports that it can't find a command called [0-9] and grep complains about not getting any argument.

Even if using a standard sh as opposed to the Bourne shell, I would recommend that you quote ^. For instance ^ is a globbing operator in zsh when the extendedglob option is enabled.

In any case, if not ^, you have to quote [0-9] since those are globbing operators. [0-9] would be expanded by the shell to the list of files in the current directory whose name is a single digit.

So:

ls /a | grep '^[0-9]'

Incidentally, in the Bourne shell

ls /a ^ grep '^[0-9]'

would also work.

Solution 3

You don't need ls and grep for this; you can use a simple glob /a/[0-9]*:

echo /a/[0-9]*
ls /a/[0-9]*
grep foo /a/[0-9]*

If you're using this in a script, beware that parsing ls output is a bad idea.

Solution 4

I agree with l0b0 grep is a bad idea here but anyway, here is an explanation of the issue and a workaround. On Solaris 10 and older, /bin/sh is an antiquated shell that shouldn't be used for anything but running legacy scripts. You really should use ksh, bash or /usr/xpg4/bin/sh instead.

The root cause here is ^ used to be the original way to specify a pipe in the early Unix times. Solaris /bin/sh inherited this archaelogical feature.

The workaround is then quite simple, just escape the caret one of these ways:

ls /a |grep \^[0-9]

or

ls /a |grep "^[0-9]"

or

ls /a |grep '^[0-9]'
Share:
12,570
BitsOfNix
Author by

BitsOfNix

Working mainly with Solaris and Linux. System administration!

Updated on September 18, 2022

Comments

  • BitsOfNix
    BitsOfNix over 1 year

    I'm facing a problem and trying to find a solution that works in sh. If I could use bash this code would work:

    ls /a|grep ^[0-9]
    

    Unfortunately this is not the case with sh, and yes I need to use sh. :) Running in sh i get

    ls /a |grep ^[0-9]
    [0-9]: not found
    Usage: grep -hblcnsviw pattern file . . .
    

    If I remove the ^ the code works but I need only the files that start with numbers and not the ones that contains numbers. Example, I need the files that are like:

    12.00.2
    2.222.1234.12
    

    from the grep man page I should be able to use ^.

    For the time being my implementation was done by using:

    ls /a|grep -v [a-z]|grep -v [A-Z]
    

    As this will remove all the files that contains chars, but still if a file is .123.33 it will show up.

    • Admin
      Admin almost 11 years
      Can you use egrep instead of grep?
    • Admin
      Admin almost 11 years
      tip: grep -v [a-z]|grep -v [A-Z] == grep -v "[a-z]\|[A-Z]"
    • Admin
      Admin almost 11 years
      it wouldn't work well, I tried with egrep and no luck, but the solution provided by slm works like a charm :)
    • Admin
      Admin almost 11 years
      @rush, that syntax is not portable and will not work in the OP's Solaris. grep -v '[a-zA-Z]' or grep -ve '[a-z]' -e '[A-Z]' or grep -vE '[a-z]|[A-Z]' are standard though (though the behaviour is locale dependant).
  • Anthon
    Anthon almost 11 years
    egrep is deprecated (according to the man page), should recommend the use of grep -E
  • BitsOfNix
    BitsOfNix almost 11 years
    so I guess that bash interprets the ^ while when using sh it is up to grep, correct? and thanks a lot.
  • slm
    slm almost 11 years
    Yes, bash is interpreting those instead of grep. I was surprised that you could pass those arguments bare like that w/o double quotes. I've only ever double quoted them to grep. You could've also put single quotes around them too.
  • Stéphane Chazelas
    Stéphane Chazelas almost 11 years
    The first one would fail if there were a ^0 and ^1 file in the current directory though. You beat me by 7 seconds on the issue's Bourne source ;)
  • Stéphane Chazelas
    Stéphane Chazelas almost 11 years
    You don't need extended REs here. That syntax works as well with BREs as with EREs so the e or -E are superfluous.
  • jlliagre
    jlliagre almost 11 years
    @StephaneChazelas Why would the first one fail ? I just checked and it worked just fine.
  • Stéphane Chazelas
    Stéphane Chazelas almost 11 years
    Because the shell would expand it to ls /a | grep '^0' '^1'. That is, it would search for lines starting with 0 in ^1 and ignore the output of ls.
  • jlliagre
    jlliagre almost 11 years
    @StephaneChazelas Got it, I overlook the "and". Thanks.