sh and grep numbers only
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]'
BitsOfNix
Working mainly with Solaris and Linux. System administration!
Updated on September 18, 2022Comments
-
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 almost 11 yearsCan you use egrep instead of grep?
-
Admin almost 11 yearstip:
grep -v [a-z]|grep -v [A-Z]
==grep -v "[a-z]\|[A-Z]"
-
Admin almost 11 yearsit wouldn't work well, I tried with egrep and no luck, but the solution provided by slm works like a charm :)
-
Admin almost 11 years@rush, that syntax is not portable and will not work in the OP's Solaris.
grep -v '[a-zA-Z]'
orgrep -ve '[a-z]' -e '[A-Z]'
orgrep -vE '[a-z]|[A-Z]'
are standard though (though the behaviour is locale dependant).
-
-
Anthon almost 11 years
egrep
is deprecated (according to the man page), should recommend the use ofgrep -E
-
BitsOfNix almost 11 yearsso I guess that bash interprets the ^ while when using sh it is up to grep, correct? and thanks a lot.
-
slm almost 11 yearsYes,
bash
is interpreting those instead ofgrep
. I was surprised that you could pass those arguments bare like that w/o double quotes. I've only ever double quoted them togrep
. You could've also put single quotes around them too. -
Stéphane Chazelas almost 11 yearsThe 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 almost 11 yearsYou don't need extended REs here. That syntax works as well with BREs as with EREs so the
e
or-E
are superfluous. -
jlliagre almost 11 years@StephaneChazelas Why would the first one fail ? I just checked and it worked just fine.
-
Stéphane Chazelas almost 11 yearsBecause the shell would expand it to
ls /a | grep '^0' '^1'
. That is, it would search for lines starting with0
in^1
and ignore the output ofls
. -
jlliagre almost 11 years@StephaneChazelas Got it, I overlook the "and". Thanks.