1

Would there be a way to use the output of ls -ltr with xargs?

Assume that the result of ls is one file as below.

ls -ltr | tail -1 | xargs -I{} open {}

For comparison, I use the following command to use find to move files:

find ~/Downloads/ -iname '*hello*' -print0 | xargs -0 -I{} mv {} ./

Can we somehow use NUL character?


[Solved]
As mentioned in the @illkachu's comments, the following works but is not suggested.

somecmd "$(ls -tr | tail -1)"

What Stéphane suggests seem be alternatives.

8
  • 3
    Using the output of ls is number 1 in BashPitfalls. If you can tell what you want to do, we might be able to point to a better solution
    – ilkkachu
    Nov 29, 2017 at 22:19
  • Maybe this Q if you want to process one or more of the newest files? remove oldest files. At least take a peek at the zsh solutions.
    – ilkkachu
    Nov 29, 2017 at 22:28
  • It is generally a really bad idea to parse the output of ls. You should probably look into either using find or simple shell globbing to get your list of files to process. Extensive further reading on the subject can be found here.
    – DopeGhoti
    Nov 29, 2017 at 22:32
  • 1
    @villybyun, for one file: somecmd "$(ls -tr | tail -1)" -- That will burn in a number of edge cases, most of which involve dashes, control characters or newlines in file names. I already feel like I've done something horrible, just writing that.
    – ilkkachu
    Nov 29, 2017 at 22:38

2 Answers 2

2

Generally, you wouldn't as the output of ls is not post-processable reliably.

For instance:

open -- "$(ls -t | head -n 1)"

doesn't work if the name of newest file contains newline characters.

Ideally, you'd want:

ls -zt | head -zn1 | xargs -r0 open --

But unfortunately, I don't know of any ls implementation that supports a -z/-0 option, and the maintainers of GNU ls at least declined several times to add it.

Now, there are other ways with some implementations.

With the GNU and ast-open implementations of ls, in the C locale, the output with the --quoting-style=shell-always option is post-processable by zsh, ksh93 or bash:

export LC_ALL=C
eval "files=($(ls --quoting-style=shell-always -t))"

open -- "${files[0]}" # $files[1] with zsh

Though in zsh, you'd just do

open ./*(om[1])

or:

open ./Ctrl+Xm

as zsh has built-in support to sort files by modification time (and many other criteria that go far beyond ls capabilities).

FreeBSD ls has a --libxo option to generate json or xml output, so you could do:

ls --libxo=json -t | perl -MJSON::PP -0777 -l0 -ne '
  print decode_json($_)
    ->{"file-information"}
    ->{directory}->[0]
    ->{entry}->[0]
    ->{name}' | xargs -r0 open --

But then it would be simpler to do the whole thing in perl.

5
  • I don't see the issue with using tr to replace tabs for nulls ls -A | tr '\n' '\0' | xargs -L 1 -0 echo
    – Ray Foss
    Jun 12, 2019 at 15:03
  • @RayFoss, you're missing the point. That still doesn't work for file names that contain newline characters. Jun 12, 2019 at 16:25
  • That zsh bit open ./*(om[1]) is something special… to the .zshrc file with you!
    – visyoual
    Jul 28, 2020 at 13:06
  • @StéphaneChazelas, it does when I add it as an alias. I was simply saying i'd never seen it, and that it was a gem. I've already added it and functions beautifully.
    – visyoual
    Jul 28, 2020 at 13:38
  • @visyoual. Ah OK, I'm with out now. I thought you said something along the lines of the feature is specific to my .zshrc. Jul 28, 2020 at 13:40
1

As you already have been told: In general this is not the approach you want to chose. However, as a start:

ls -ltr | awk '/^-/ { print $9; }' | xargs

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.