Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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.

share|improve this question
    
Can you use egrep instead of grep? –  slm Jun 5 '13 at 12:48
1  
tip: grep -v [a-z]|grep -v [A-Z] == grep -v "[a-z]\|[A-Z]" –  rush Jun 5 '13 at 12:59
    
it wouldn't work well, I tried with egrep and no luck, but the solution provided by slm works like a charm :) –  BitsOfNix Jun 5 '13 at 13:03
1  
@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). –  Stéphane Chazelas Jun 5 '13 at 13:44

4 Answers 4

up vote 3 down vote accepted

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]'
share|improve this answer
    
egrep is deprecated (according to the man page), should recommend the use of grep -E –  Anthon Jun 5 '13 at 13:01
    
so I guess that bash interprets the ^ while when using sh it is up to grep, correct? and thanks a lot. –  BitsOfNix Jun 5 '13 at 13:02
    
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. –  slm Jun 5 '13 at 13:04
1  
You don't need extended REs here. That syntax works as well with BREs as with EREs so the e or -E are superfluous. –  Stéphane Chazelas Jun 5 '13 at 13:47

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 Thomson 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.

share|improve this answer
    
Thanks for the lesson 8-). –  slm Jun 5 '13 at 14:07
    
Thanks a lot for the explanation!! :) –  BitsOfNix Jun 6 '13 at 8:14

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.

share|improve this answer

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|improve this answer
1  
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 Jun 5 '13 at 13:38
    
@StephaneChazelas Why would the first one fail ? I just checked and it worked just fine. –  jlliagre Jun 5 '13 at 16:12
    
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. –  Stéphane Chazelas Jun 5 '13 at 16:49
    
@StephaneChazelas Got it, I overlook the "and". Thanks. –  jlliagre Jun 5 '13 at 17:03

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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