8

I'm trying to create a macro for Keyboard Maestro for OS X doing the following:

  1. Get name of newest file in a directory on my disk based on date created;
  2. Paste the text "newest file: " plus the name of the newest file.

One of its options is to "Execute a shell script", so I thought that would do it for 1. After Googling around a bit I came up with this:

cd /path/to/directory/
ls -t | head -n1

This sorts it right, and returns the first filename. However, it also seems to includes a line break, which I do not want. As for 2: I can output the text "newest file: " with a different action in the app, and paste the filename behind that. But I'm wondering if you can't return "random text" + the outcome of the ls command.

So my question is: can I do this only using the ls command? And how do I get just the name of the latest file without any linebreaks or returns?

Casimir et Hippolyte
  • 88,009
  • 5
  • 94
  • 125
Alec
  • 9,000
  • 9
  • 39
  • 43
  • To get the random text you could do something like: `head -c 12 /dev/urandom | base64`. Oh, wait, you mean *arbitrary* text. Sorry, I was confused. – Dennis Williamson May 15 '10 at 03:05

5 Answers5

13

Since you're already using pipes, just throw another one in there:

ls -t | head -n1 |awk '{printf("newest file: %s",$0)}'

(Note that the "printf" does not include a '\n' at the end; that gets rid of the linebreak)

Edit:

With Arkku's suggestion to exit awk after the first line, it looks like:

ls -t | awk '{printf("newest file: %s",$0);exit}'
David Gelhar
  • 27,873
  • 3
  • 67
  • 84
4
cd /path/to/directory/
echo -n "random text goes here" $(ls -t | head -n1)

If you want, you can add more text on the end in the same way.

Andrew McGregor
  • 31,730
  • 2
  • 29
  • 28
  • Thanks! This still had the return for some reason in the app, even though the -n didn't show it in the Terminal itself. But the echo followed by a command will come in handy for some other things as well :) – Alec May 15 '10 at 01:22
4

Using output of ls is bad practice.

find -type f -printf '%T+ %p\n' | sort -r | head -n 1

diimdeep
  • 1,096
  • 17
  • 27
  • Why's using `ls` output a bad practice? Not disagreeing, just curious about the reasoning. Concerns about code injection? – Ty Mick Oct 24 '22 at 20:42
2

You can do that in bash in a single statement like so:

echo -n "newest file: $(ls -t |head -n1)"

You can also remove that newline without echo:

ls -t |head -n1 |tr -d '\n'

Make sure ls doesn't output colors to non-tty streams (i.e. specify color by ls --color=never or ls --color=auto or not at all).

The ls solution will output files of any kind sorted by modification time. If you want only regular files or if you don't want directories then you can use find and xargs:

echo -n "newest file: $(find . -maxdepth 1 -type f -print0 |xargs -0 ls -t)"
wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
-1

You can't do it with only ls. However, as echo is generally built into the shell, it doesn't really add any overhead into the script. To get just the name of the file, I'd suggest:

echo -n "newest: $(ls -t1 | head -n1)"

If, for some reason, you really want to eliminate the head, then I suppose you could go for something like:

ls -t1 | ( read n; echo -n "newest: $n")

(read is built into the shell, head isn't.)

Note that these solutions do not recurse into subdirectories, since that was not specified in the question. In fact, subdirectories may be printed as the newest "file".

Arkku
  • 41,011
  • 10
  • 62
  • 84
  • So, someone downvoted this (and some other answers) over 7 years later. I'd like to point out that this answer was posted mainly to answer the precise question "can I do this only using the `ls` command" (the accepted answer using `awk`, to which I contributed a suggestion, was already posted). It is not my fault if this doesn't answer some other question, even if the question turns up in search results. – Arkku Dec 13 '17 at 15:40