Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to assign the result of an expression to a variable and concatenate it with a string, then echo it. Here's what I've got:

#!/bin/bash
cd ~/Desktop;
thefile= ls -t -U | grep -m 1 "Screen Shot";
echo "Most recent screenshot is: "$thefile;

But, that outputs:

Screen Shot 2011-07-03 at 1.55.43 PM.png
Most recent screenshot is: 

So, it looks like that isn't getting assigned to $thefile, and is being printed as it's executed.

I'm rather new to this; I'm sure I'm just missing something basic.

Thanks for your patience!

share|improve this question
add comment

1 Answer 1

up vote 33 down vote accepted

A shell assignment is a single word, with no space after the equal sign. So what you wrote assigns an empty value to thefile; furthermore, since the assignment is grouped with a command, it makes thefile an environment variable and the assignment is local to that particular command, i.e. only the call to ls sees the assigned value.

You want to capture the output of a command, so you need to use command substitution:

thefile=$(ls -t -U | grep -m 1 "Screen Shot")

(Some literature shows an alternate syntax thefile=`ls …`; the backquote syntax is equivalent to the dollar-parentheses syntax except that quoting inside backquotes is weird sometimes, so just use $(…).)

Other remarks about your script:

  • Combining -t (sort by time) with -U (don't sort) doesn't make sense; just use -t.
  • Rather than using grep to match screenshots, it's clearer to pass a wildcard to ls and use head to capture the first file:

    thefile=$(ls -t *"Screen Shot"* | head -n 1)
    
  • It's generally a bad idea to parse the output of ls. This could fail quite badly if you have file names with nonprintable characters. However, sorting files by date is difficult without ls, so it's an acceptable solution if you know you won't have unprintable characters or backslashes in file names.

  • Always use double quotes around variable substitutions, i.e. here write

    echo "Most recent screenshot is: $thefile"
    

    Without double quotes, the value of the variable is reexpanded, which will cause trouble if it contains whitespace or other special characters.

  • You don't need semicolons at the end of a line. They're redundant but harmless.
  • In a shell script, it's often a good idea to include set -e. This tells the shell to exit if any command fails (by returning a nonzero status).

If you have GNU find (in particular if you're running non-embedded Linux or Cygwin), there's another approach to finding the most recent file: have find list the files and their dates, and use sort and tail to extract the youngest file.

thefile=$(find -maxdepth 1 -type f -name "*Screen Shot*" -printf "%T@ %p" |
          sort -k 1n | tail -n 1)

If you're willing to write this script in zsh instead of bash, there's a much easier way to catch the newest file, because zsh has glob qualifiers that permit wildcard matches not only on names but also on file metadata. The (om[1]) part after the pattern is the glob qualifiers; om sorts matches by increasing age (i.e. by modification time, newest first) and [1] extracts the first match only. The whole match needs to be in parentheses because it's technically an array, since globbing returns a list of files, even if the [1] means that in this particular case the list contains (at most) one file.

#!/bin/zsh
set -e
cd ~/Desktop
thefile=(*"Screen Shot"*(om[1]))
echo "Most recent screenshot is: $thefile"
share|improve this answer
2  
Wow! More info than I possibly could have hoped for. Thank you many times for your answer; I really appreciate all the effort you put into this! You've just shown me that I really, really have a lot to learn. I'm off to buy a book on bash :P. –  Nathan G. Jul 4 '11 at 0:10
1  
That's what I would call the definitive answer! :) –  alex Jul 4 '11 at 6:19
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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