Pipe the output of a command if it is successful

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)

In a pipe line, all commands are started and run concurrently, not 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

Note that it assumes file names don't contain newline characters. Using xargs would also mean problems with blank characters, single and double quotes and backslashes. Leaving variables unquoted would mean problems with space, tab and wildcard characters. Forgetting -- would mean problems with filenames starting with -.

To get the basename of the oldest file with zsh without any of those restrictions on characters (also avoids the problem of the limited size of arguments to a command):

 first_file_name=($MY_DIR/FILE.*.xml(Om[1]:t))

If there's no match, that command will fail and abort the script. You can also do:

 first_file_name=($MY_DIR/FILE.*.xml(NOm[1]:t))

In which case the first_file_name array will contain 1 element if there's a match or 0 if not. You can then do:

 if (($#first_file_name)); then
    printf 'Match: %s\n' $first_file_name
 else
    echo >&2 No match
 fi

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.

Tags:

Shell

Pipe

Output