14

I need to build a script that shows files in the same order as the default Downloads folder in the dock, ordered by Date Added, newest first. I can't seem to find the option in ls.

Any other way to do it?

3
  • Display it where?
    – Rob
    Commented Mar 21, 2013 at 16:53
  • Command line!.Got it! I ended up writing a one liner that does the trick. Since I dont have much reputation, I cannot answer my own question yet, I'll do it later. Commented Mar 21, 2013 at 17:03
  • Welcome to the site Ramiro - you should be able to answer your own question any time - but there will be a restriction for you to "mark as accepted" your answer. Feel free to edit my answer to suit your needs or provide your own answer if/when you like.
    – bmike
    Commented Mar 21, 2013 at 18:02

3 Answers 3

9

Simpler (Faster) solution:

mdls -name kMDItemFSName -name kMDItemDateAdded -raw * | \
xargs -0 -I {} echo {} | \
sed 'N;s/\n/ /' | \
sort
7
  • 1
    yep, much better :) Commented Aug 3, 2015 at 19:40
  • 1
    Could someone detail what each of those lines do? Also, can this solution be performed in Terminal as individual command lines (sequentially, one after the other), or only within a script?
    – EJ Mak
    Commented Sep 20, 2018 at 15:37
  • 1
    Line 1: mdls is Mac's metadata list tool. Type man mdls for the documentation. This doesn't work in other Linux distress. There are many metadata keys. The -name flags pick off just the two we want, the file name and its date added. The -raw flag separates the returned values with a null character. The star lists all files. You substitute the directory and any other glob filters you want. The pipe outputs to the next command. IOW this is a single command. You can indeed do this interactively in the terminal. If you wanted to do them individually, you could output each step to a file. Commented Dec 27, 2020 at 16:53
  • 1
    Line 2: Sometimes the pipes don't put the output where the next command needs the argument to go. The -0 flag says the input coming from the prior pipe is delimited with a null character. The -I flag sets a replacement string. The braces are a convention. You can use any character you don't expect in the input. I tend to use a percent sign. In this case, xargs runs the echo command for each output from the prior pipe, placing it where the replacement string, "{}", is. Then that gets piped to the next command. Commented Dec 27, 2020 at 17:05
  • 2
    Line 3: This is the stream editor, sed. The sed tool edits text, and does the usual things you would expect with strings, but it has its own syntactical flavors. Look up man sed to see more. There are two commands here, N and s, meaning next and substitute. Jose chose N here because we're getting two metadata keys at a time. For each input, we're saying, okay, got one. Before doing anything, get another one, too. Now run the s command. Here we say for any newline character, substitute a space. Then pipe those results to the next tool. Commented Dec 27, 2020 at 17:14
4

The date added is stored as metadata item kMDItemDateAdded and the mdls command will expose the data for each file passed as an argument to it.

So, to dump the date added for all files in Downloads in whatever arbitrary order * gets expanded by your shell, you can:

mdls -name kMDItemDateAdded ~/Downloads/*

You'll need to hack together some combination of find and sed/awk/perl/whatever to assemble a replacement for ls but perhaps mdfind can be called by your script rather than needing to reinvent ls and parsing that output.

2
  • 1
    Yes! I found it later and made a beautiful one liner that teached me a lot of things :) Thanks for the help Commented Mar 21, 2013 at 20:01
  • 2
    Paste that one liner in by editing my answer - share the knowledge!
    – bmike
    Commented Mar 21, 2013 at 20:55
2

Well, as usual, after writing the question I start digging for metadata content in files, and ended up writing this:

ls -a | \
grep -v '^\.$\|^\.\.$' | \
xargs -I {} mdls -name kMDItemFSName -name kMDItemDateAdded {} | \
sed 'N;s/\n//' | grep -v '(null)' | \
awk '{print $3 " " $4 " " substr($0,index($0,$7))}' | \
sort -r

Basically it: 1. list all files 2. filters out . and .. 3. gets the name and date added, one line after the other 4. merges every two lines into 1 line 5. extracts the date, time and name 6. sorts it in reverse (since datetime is upfront, it sorts by datetime)

Hope it helps someone else! :)

@bmike actually, the site imposed me a restriction to answer my own question only after 8 hours of posting my question, due to my lack of reputation :D

2
  • oh, I split the one liner in several lines for clarity only :) Commented Mar 22, 2013 at 2:58
  • 1
    Use ls -A instead of -a so you don't have to grep -v for . and ...
    – mfilej
    Commented Nov 10, 2013 at 10:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .