82

I have a file where I want to grep for lines that start with either -rwx or drwx AND end in any number.

I've got this, but it isnt quite right. Any ideas?

grep [^.rwx]*[0-9] usrLog.txt
Toto
  • 89,455
  • 62
  • 89
  • 125
texasCode
  • 821
  • 1
  • 6
  • 3

6 Answers6

65

The tricky part is a regex that includes a dash as one of the valid characters in a character class. The dash has to come immediately after the start for a (normal) character class and immediately after the caret for a negated character class. If you need a close square bracket too, then you need the close square bracket followed by the dash. Mercifully, you only need dash, hence the notation chosen.

grep '^[-d]rwx.*[0-9]$' "$@"

See: Regular Expressions and grep for POSIX-standard details.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 3
    Or `grep -x '[-d]rwx.*[0-9]'`. – ephemient Jan 26 '11 at 00:04
  • On Linux, yes - or where GNU grep is used. The version I quoted will work on all Unix variants, which I would submit makes it better. – Jonathan Leffler Jan 26 '11 at 00:14
  • 2
    `-x` is POSIX. Bracket following dash: `[[.-.][.].]]` (which, granted, is less readable than `[]-]`). I *believe* this is also POSIX… – ephemient Jan 26 '11 at 00:15
  • 2
    @ephemient: oh, yes, 'grep -x' is in POSIX and has been for ages - 2008, 2004, 1997 (SUS). My bad...I've never bothered to look for such an option because '^....$' is perfectly routine and uses one character less than a separate '-x' option. – Jonathan Leffler Jan 26 '11 at 00:40
39

It looks like you were on the right track... The ^ character matches beginning-of-line, and $ matches end-of-line. Jonathan's pattern will work for you... just wanted to give you the explanation behind it

Ray
  • 4,829
  • 4
  • 28
  • 55
  • 6
    Not entirely on the right track, though. It's significant to note that characters inside a `[ ]` character class behave significantly differently than they would in other parts of the regex. – ephemient Jan 26 '11 at 00:35
9

It should be noted that not only will the caret (^) behave differently within the brackets, it will have the opposite result of placing it outside of the brackets. Placing the caret where you have it will search for all strings NOT beginning with the content you placed within the brackets. You also would want to place a period before the asterisk in between your brackets as with grep, it also acts as a "wildcard".

grep ^[.rwx].*[0-9]$

This should work for you, I noticed that some posters used a character class in their expressions which is an effective method as well, but you were not using any in your original expression so I am trying to get one as close to yours as possible explaining every minor change along the way so that it is better understood. How can we learn otherwise?

Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
Bria
  • 91
  • 1
  • 1
7

You probably want egrep. Try:

egrep '^[d-]rwx.*[0-9]$' usrLog.txt
Brad Koch
  • 19,267
  • 19
  • 110
  • 137
Nate
  • 484
  • 3
  • 6
1

are you parsing output of ls -l?

If you are, and you just want to get the file name

find . -iname "*[0-9]" 

If you have no choice because usrLog.txt is created by something/someone else and you absolutely must use this file, other options include

awk '/^[-d].*[0-9]$/' file

Ruby(1.9+)

ruby -ne 'print if /^[-d].*[0-9]$/' file

Bash

while read -r line ; do  case $line in [-d]*[0-9] ) echo $line;  esac; done < file
kurumi
  • 25,121
  • 5
  • 44
  • 52
0

Many answers provided for this question. Just wanted to add one more which uses bashism-

#! /bin/bash
while read -r || [[ -n "$REPLY" ]]; do
[[ "$REPLY" =~ ^(-rwx|drwx).*[[:digit:]]+$ ]] && echo "Got one -> $REPLY"
done <"$1"

@kurumi answer for bash, which uses case is also correct but it will not read last line of file if there is no newline sequence at the end(Just save the file without pressing 'Enter/Return' at the last line).

some_guy
  • 83
  • 8