Search code examples
bashpipeline

Bash- how to handle pipeline with multiple argument and -o pipeline enable


So I have this pipeline with set -o pipefail in the top of script.

 local numbr_match
    numbr_match=$(ls -t1 logs/repologs | grep "$name" | wc --lines)
 if [ ! -z "${numbr_match}" ] && [ "${numbr_match}" -le 
   "$logrot_keep"];then
    echo "Found $numbr_match backups matching '$name', don't need to 
     remove until we have more than $logrot_keep"
 else

If ls -t1 are not finding anything therefore grep fails I belive whole pipeline fails with pipefail. Whats the best solution to use to come around this?


Solution

  • The problem is not the ls.

    Even if logs/repologs is an empty directory, ls would still set exit status 0. If log/repologs does not exist, ls sets exit code 2. You could catch the latter by guarding the whole pipe with a [[ -d logs/repologs ]] && ...

    The main problem is the grep:

    If the directory is empty, grep does not get any input, and therefore your pipefail fires. You could avoid this by doing a

    ls -a logs/repologs
    

    but this produces at least two additional entries (. and ..) and your wc count would be off by 2. It would also include other hidden entries in the directories.

    However, what's the purpose of the whole statement? If you just want to count the number of non-hidden entries in the directory, your method is unreliable anyway, for if you have a file where the name contains an embedded newline character, it would be counted as two entries.

    A more reasonable approach would be to load all the files into an array and take the length of the array:

    shopt -s nullglob
    files=(logs/repologs/*"$name"*)
    echo Number of non-hidden entries : ${#files[*]}
    

    UPDATE:

    For completeness: My solution is a bit different to yours in the following respect:

    Assume that you would set

    name=foo.bar
    

    In your solution, entries fooxbar and fooybar would be counted as well, while in my solution, only a literal foo.bar would be counted. The same applies to other characters which have a special meaning inside a simple regular expression.