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.
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`

I wanted to execute the second command (head -1) only if the first command is successful. How do I improve this command?

share|improve this question
    
What do you mean by successful? ls will not fail. –  Matteo Jul 23 '13 at 13:12
1  
But the glob can fail if there are no matching files. –  tripleee Jul 23 '13 at 13:17

4 Answers 4

up vote 5 down vote accepted

Try this:

INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml | head -1 | xargs -r basename`

Passing xargs the -r flag will cause it to only run basename if reads at least one item from standard input (head -1).

head -1 will run but you won't see or capture any output from it.

Also, if you don't want the user to see any error output from ls, you can redirect ls's stderr stream to /dev/null.

INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename`

Also note that I added quotation marks around $MY_DIR. That way, the command will not fail if $MY_DIR contains spaces.

If you're using a modern shell such as bash, you should use a $( ) capture shell instead of backticks. You should also consider changing the style of your variables. You should generally avoid using all-uppercase variable names in scripts. That style is generally reserved for reserved and environmental variables.

input_file=$(ls -rt "$my_dir"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename)
share|improve this answer
    
Doesn't this b0rk if there are no files? –  Mel Boyce Jul 23 '13 at 13:44
    
Actually: ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basename works. –  Mel Boyce Jul 23 '13 at 13:48
    
@MelBoyce: I've added that to my answer. Thanks. –  paraxor Jul 23 '13 at 13:51
    
ls is a tool for interactively looking at file information. Its output is formatted for humans and will cause bugs in scripts. Use globs or find instead. Understand why: mywiki.wooledge.org/ParsingLs –  cinelli Jul 23 '13 at 15:56
    
@cinelli: That is true. I was just answering the question. –  paraxor Jul 23 '13 at 16:09

Find the latest modified file in a directory:

latest() {
  local file path=${1:-.} ext=${2-} latest
  for file in "${path%/}"/*"$ext"; do 
    [[ $file -nt $latest ]] && latest=$file
  done
  [[ $latest ]] && printf '%s\n' "$latest"
}

Usage: latest [directory/path/ [.extension]]

Instead of calling out to basename, use parameter expansion.

in_file=$(latest in/my/dir .xml)
base_fn=${in_file##*/} base_fn=${base_fn%.*}

In a directory with these contents:

foo.xml bar.xml baz.xml newest.xml

The contents of the base_fn variable would be: newest

To use this properly to serve the purpose of your request:

check_dir=/path/to/check
check_ext=.xml
if in_file=$(latest "$check_dir" "$check_ext"); then
  base_fn=${in_file##*/} base_fn=${base_fn%.*}
else
  printf '%s\n' "No file found in $check_dir" >&2
fi

EDIT: upon review of the question, i have realized that the ls command in question is looking for the oldest file in a directory. this same function could be renamed to oldest and have [[ $file -ot $oldest ]] && oldest=$file instead to achieve the same effect. apologies for any confusion.

the important thing to note is that you absolutely, under no circumstances ever in mankind, should not parse the output of ls. never.

share|improve this answer

In a pipe line, all commands are started concurrently, note one after the other. So you need to store the output somewhere.

if ls_output=$(ls -rtd -- "$MY_DIR"/FILE.*.xml); then
  first_file=$(printf '%s\n' "$ls_output" | head -n 1)
  first_file_name=$(basename -- "$first_file")
fi
share|improve this answer

I think that the best option here is:

ls -rf $MY_DIR/FILE.*.xml
if [ $? -eq 0 ]; then
      INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml|head -1|xargs basename `
else
      echo "Error!"
fi

if there is no file then the return code of ls is 2 but if it finds some file will be 0.

share|improve this answer
2  
Instead of comparing $? against 0, you can do this: if ls -rf $MY_DIR/FILE.*.xml ; then. –  paraxor Jul 23 '13 at 13:27
    
Also, you can redirect the output of the first comand to /dev/null. ls -rf $MY_DIR/FILE.*.xml &> /dev/null. That way, the user won't see the extra output. –  paraxor Jul 23 '13 at 13:36
    
Thank you all :) –  Govind Kailas Jul 25 '13 at 6:32

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.