5

How do I tell grep to only print out lines if the "filename" matches when I'm piping through ls? I want it to ignore everything on each line until after the timestamp. There must be some easy way to do this on a single command.

As you can see, without it, if I searched for the file "rwx", it would return not only the line with rwx.c, but also the first three lines because of permissions. I was going to use AWK but I want it to display the whole last line if I search for "rwx".

Any ideas?

EDIT: Thanks for the hacks below. However, it would be great to have a more bug-free method. For example, if I had a file named "rob rob", I wouldn't be able to use the stated solutions.

drwxrwxr-x 2 rob rob  4096 2012-03-04 18:03 .
drwxrwxr-x 4 rob rob  4096 2012-03-04 12:38 ..
-rwxrwxr-x 1 rob rob 13783 2012-03-04 18:03 a.out
-rw-rw-r-- 1 rob rob  4294 2012-03-04 18:02 function1.c
-rw-rw-r-- 1 rob rob   273 2012-03-04 12:54 function1.c~
-rw-rw-r-- 1 rob rob    16 2012-03-04 18:02 rwx.c
-rw-rw-r-- 1 rob rob    16 2012-03-04 18:02 rob rob
mathjacks
  • 335
  • 2
  • 4
  • 11
  • If you only want the file names, don't use `ls -al`; use plain `ls -a` to get the interesting names, and then `ls -ld` to get the details for them? Parsing the output from `ls` is notoriously difficult, even before you try thinking about file names containing spaces. The good news: even as the date formats change, the number of columns in the time remains constant (two white space separated values). – Jonathan Leffler Mar 04 '12 at 23:29
  • I agree with Jonathan ; if all you are trying to do is list files, then pass the correct options to ls. – souser Mar 04 '12 at 23:37
  • Actually, my comment about date columns isn't entirely accurate; your `ls -l` is displaying two columns; mine displays three for recent files: `-r--r--r-- 1 jleffler staff 26676 Mar 3 21:44 ccs.nmd` and old files `-r--r--r-- 1 jleffler staff 6510 Mar 17 2003 README,v`. – Jonathan Leffler Mar 04 '12 at 23:41

10 Answers10

15

The following will list only file name, and one file in each row.

$ ls -1     

To include . files

$ ls -1a 

Please note that the argument is number "1", not letter "l".

j0k
  • 22,600
  • 28
  • 79
  • 90
James
  • 159
  • 1
  • 2
3

Why don't you use grep and match the file name following the timestamp?

grep -P "[0-9]{2}:[0-9]{2} $FILENAME(\.[a-zA-Z0-9]+)?$"

The [0-9]{2}:[0-9]{2} is for the time, the $FILENAME is where you'd put rob rob or rwx, and the trailing (\.[a-zA-Z0-9]+)? is to allow for an optional extension.

Edit: @JonathanLeffler below points out that when files are older than bout 6 months the time column gets replaced by a year - this is what happens on my computer anyhow. You could do ([0-9]{2}:[0-9]{2}|(19|20)[0-9]{2}) to allow time OR year, but you may be best of using awk (?).

[foo@bar ~/tmp]$ls -al
total 8
drwxrwxr-x  2 foo foo 4096 Mar  5 09:30 .
drwxr-xr-- 83 foo foo 4096 Mar  5 09:30 ..
-rw-rw-r--  1 foo foo    0 Mar  5 09:30 foo foo
-rw-rw-r--  1 foo foo    0 Mar  5 09:29 rwx.c
-rw-rw-r--  1 foo foo    0 Mar  5 09:29 tmp

[foo@bar ~/tmp]$export filename='foo foo'

[foo@bar ~/tmp]$echo $filename
foo foo

[foo@bar ~/tmp]$ls -al | grep -P "[0-9]{2}:[0-9]{2} $filename(\.[a-zA-Z0-9]+)?$"
-rw-rw-r--  1 cha66i cha66i    0 Mar  5 09:30 foo foo

(You could additionally extend to matching the whole line if you wanted:

^                              # start of line
[d-]([r-][w-][x-]){3} +        # permissions & space (note: is there a 't' or 's'
                               # sometimes where the 'd' can be??)
[0-9]+                         # whatever that number is
[\w-]+ [\w-]+ +                # user/group (are spaces allowed in these?)
[0-9]+ +                       # file size (modify for -h switch??)
(19|20)[0-9]{2}-               # yyyy (modify if you want to allow <1900)
(1[012]|0[1-9])-               # mm
(0[1-9]|[12][0-9]|3[012]) +    # dd
([01][0-9]|2[0-3]):[0-6][0-9] +# HH:MM (24hr)
$filename(\.[a-zA-Z0-9]+)?     # filename & optional extension
$                              # end of line

. You get the point, tailor to your needs.)

mathematical.coffee
  • 55,977
  • 11
  • 154
  • 194
  • 2
    Beware old files - the time format in the `ls -l` listing loses the time and gains the year when the file is older than about 6 months old. – Jonathan Leffler Mar 04 '12 at 23:45
  • :S thanks for that pickup. and I notice that my date format is different to OP's too - hopefully stays constant enough for a given machine? – mathematical.coffee Mar 04 '12 at 23:51
2

Assuming that you aren't prepared to do:

ls -ld $(ls -a | grep rwx)

then you need to exploit the fact that there are 8 columns with space separation before the file name starts. Using egrep (or grep -E), you could do:

ls -al | egrep "^([^ ]+ +){8}.*rwx"

This looks for 'rwx' after the 8th column. If you want the name to start with rwx, omit the .*. If you want the name to end with rwx, add a $ at the end. Note that I used double quotes so you could interpolate a variable in place of the literal rwx.

This was tested on Mac OS X 10.7.3; the ls -l command consistently gives three columns for the date field:

-r--r--r--  1 jleffler  staff   6510 Mar 17  2003 README,v
-r--r--r--  1 jleffler  staff  26676 Mar  3 21:44 ccs.nmd

Your ls -l seems to be giving just two columns, so you'd need to change the {8} to {7} for your machine - and beware migrating between systems.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

Well, if you're working with filenames that don't have spaces in them, you could do something like this:

grep 'rwx\S*$'
Amber
  • 507,862
  • 82
  • 626
  • 550
  • what exactly does that do? is there an alternative for file names with spaces? – mathjacks Mar 04 '12 at 23:27
  • It matches "rwx followed by any number of non-space characters followed by the end of a line". There isn't really a good alternative for file names with spaces because then there's no way to distinguish the break between time and filename, versus a part of the filename. – Amber Mar 04 '12 at 23:30
0

This works for me, unlike ls -l & others as some folks pointed out. I like this because its really generic & gives me the base file name, which removes the path names before the file.

ls -1 /path_name |awk -F/ '{print $NF}'
ekta
  • 1,560
  • 3
  • 28
  • 57
0

Only one command you needed for this --

ls -al | gawk '{print $9}'
Bharat
  • 646
  • 1
  • 8
  • 12
0

You can use this:

ls -p | grep -v / 
Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
Gio Italy
  • 91
  • 1
  • 6
  • While this code may answer the question, it would be better to include some _context_, explaining _how_ it works and _when_ to use it. Code-only answers are not useful in the long run. – Benjamin W. Mar 24 '16 at 17:44
0

this is super old, but i needed the answer and had a hard time finding it. i didn't really care about the one-liner part; i just needed it done. this is down and dirty and requires that you count the columns. i'm not looking for an upvote here, just leaving some options for future searcher-ers.

the helpful awk trick is here -- Using awk to print all columns from the nth to the last

if YOUR_FILENAME="rob rob" and WHERE_FILENAMES_START=8

ls -al | while read x; do
  y=$(echo "$x" | awk '{for(i=$WHERE_FILENAMES_START; i<=NF; ++i) printf $i""FS; print ""}')
  [[ "$YOUR_FILENAME " = "$y" ]] && echo "$x"
done

if you save it as a bash script and swap out the vars with $2 and $1, throw the script in your usr bin... then you'll have your clean simple one-liner ;)

output will be:

> -rw-rw-r-- 1 rob rob    16 2012-03-04 18:02 rob rob

the question was for a one-liner so...

ls -al | while read x; do [[ "$YOUR_FILENAME " = "$(echo "$x" | awk '{for(i=WHERE_FILENAMES_START; i<=NF; ++i) printf $i""FS; print ""}')" ]] && echo "$x" ; done

(lol ;P)


on another note: mathematical.coffee your answer was rad. it didn't solve my version of this problem, so i didn't upvote, but i liked your regex breakdown :D

Symbolic
  • 693
  • 5
  • 10
0

As a simple hack, just add a space before your filename so you don't match the beginning of the output:

ls -al | grep '\srwx'

Edit: OK, this is not as robust as it should be. Here's awk:

ls -l | awk ' $9 ~ /rwx/ { print $0 }'
Greg Inozemtsev
  • 4,516
  • 23
  • 26
0

Aside frrm the fact that you can use pattern matching with ls, exaple ksh and bash, which is probably what you should do, you can use the fact that filename occur in a fixed position. awk (gawk, nawk or whaever you have) is a better choice for this. If you have to use grep it smells like homework to me. Please tag it that way.

Assume the filename starting position is based on this output from ls -l in linux: 56

-rwxr-xr-x  1 Administrators None    2052 Feb 28 20:29 vote2012.txt

ls -l | awk ' substr($0,56) ~/your pattern even with spaces goes here/'

e.g.,

ls -l | awk ' substr($0,56) ~/^val/'

will find files starting with "val"

jim mcnamara
  • 16,005
  • 2
  • 34
  • 51