4

I want to store the result of a command to a variable in my shell script. I cant seem to get it to work. I want the most recently dated file in the directory.

PRODUCT= 'ls -t /some/dir/file* | head -1 | xargs -n1 basename'

it wont work

Oded
  • 489,969
  • 99
  • 883
  • 1,009
user1769538
  • 85
  • 1
  • 2
  • 4
  • possible duplicate of [How to store an output of shell script to a variable in Unix?](http://stackoverflow.com/questions/10948303/how-to-store-an-output-of-shell-script-to-a-variable-in-unix) – tripleee Jan 29 '13 at 06:30

5 Answers5

5

you have two options, either $ or backsticks`.

1) x=$(ls -t /some/dir/file* | head -1 | xargs -n1 basename)

or

2) x=`ls -t /some/dir/file* | head -1 | xargs -n1 basename`

echo $x

Edit: removing unnecessary bracket for (2).

Alex
  • 5,364
  • 9
  • 54
  • 69
doniyor
  • 36,596
  • 57
  • 175
  • 260
4

The problem that you're having is that the command needs to be surrounded by back-ticks rather than single quotes. This is known as 'Command Substitution'.

Bash allows you to use $() for command substitution, but this is not available in all shells. I don't know if it's available in KSH; if it is, it's probably not available in all versions.

If the $() syntax is available in your version of ksh, you should definitely use it; it's easier to read (back ticks are too easy to confuse with single quotes); back-ticks are also hard to nest.

This only addresses one of the problems with your command, however: ls returns directories as well as files, so if the most recent thing modified in the specified directory is a sub-directory, that is what you will see.

If you only want to see files, I suggest using some version of the following (I'm using Bash, which supports default variables, you'll probably have to play around with the syntax of $1)

lastfile () 
{ 
    find ${1:-.} -maxdepth 1 -type f -printf "%T+ %p\n" | sort -n | tail -1 | sed 's/[^[:space:]]\+ //'
}

This runs find on the directory, and only pulls files from that directory. It formats all of the files like this:

2012-08-29+16:21:40.0000000000 ./.sqlite_history
2013-01-14+08:52:14.0000000000 ./.davmail.properties
2012-04-04+16:16:40.0000000000 ./.DS_Store
2010-04-21+15:49:00.0000000000 ./.joe_state
2008-09-05+17:15:28.0000000000 ./.hplip.conf
2012-01-31+13:12:28.0000000000 ./.oneclick

sorts the list, takes the last line, and chops off everything before the first space.

Barton Chittenden
  • 4,238
  • 2
  • 27
  • 46
  • `ksh` supports `$()`. I think POSIX requires it, these days. It's certainly the preferred form, especially if you need to nest them. – Carl Norum Jan 28 '13 at 18:19
  • Instead of sed, you could use `cut -d" " -f 2-` – glenn jackman Jan 29 '13 at 01:07
  • Thank you so much. I am still new to ksh. The company I work for, uses ksh to do some automation on their servers. I will try this tomorrow and let you know if I have any success. – user1769538 Jan 29 '13 at 01:43
1

You want $() (preferred) or backticks (``) (older style), rather than single quotes:

PRODUCT=$(ls -t /some/dir/file* | head -1 | xargs -n1 basename)

or

PRODUCT=`ls -t /some/dir/file* | head -1 | xargs -n1 basename`
Community
  • 1
  • 1
Carl Norum
  • 219,201
  • 40
  • 422
  • 469
1

You need both quotes to ensure you keep the name even if it contains spaces, and also in case you later want more than 1 file, and "$(..)" to run commands in background

I believe you also need the '-1' option to ls, otherwise you could have several names per lines (you only keep 1 line, but it could be several files)

PRODUCT="$(ls -1t /some/dir/file* | head -1 | xargs -n1 basename)"

Please do not put space around the "=" variable assignments (as I saw on other solutions here) , as it's not very compatible as well.

Olivier Dulac
  • 3,695
  • 16
  • 31
0

I would do something like:

Your version corrected:

PRODUCT=$(ls -t /some/dir/file* | head -1 | xargs -n1 basename)

Or simpler:

PRODUCT=$(cd /some/dir && ls -1t file* | head -1)
  • change to the directory
  • list one filename per line and sort by time/date
  • grab the first line
Yelali
  • 1