1

I have to process multiple files that I dont have the entire name for. I am running an if statement using a wildcard. for example...

if [ "ESGSN_*.SMS.EDR" ]; then
    echo "There are files to process in this run"
    for F in ESGSN_*.SMS.EDR; do
        gzip < "$F" > "$F.gz"
    done
fi

If there are multiple files or a single file this will work and zip them. But if there are no files it will still run the zip rather than just end. I was wondering if there is any way to get it to complete and move on.

I have tried using the operators "-f" and "-a" within the brackets just before the filename, but those will error out with: "binary operator expected"

for some reason the asterisk in the filename is not showing down below in the message. So the file name is "ESGSN_"*".SMS.EDR" where the double quotes is the asterisk.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
  • The asterisk wasn't appearing correctly because you didn't have your code in a code block. I've just sent up an edit proposal that will fix it for you, just need to wait for it to be approved by someone with more rep. – cryptarch Jan 10 '19 at 21:03
  • The * there won't work since it is quoted "". Globs don't expand when quoted. – Valentin Bajrami Jan 10 '19 at 21:14
  • if [[ -f *.foo ]]; then echo foo; else echo bar; fi works properly for me. Un quote the glob and you'll be fine. – DopeGhoti Jan 10 '19 at 21:17
  • "for some reason the asterisk in the filename..." ... so, is that asterisk supposed to be a literal part of the filename or a wildcard? If it's a literal, then why use for f in ... since there's only one file? – ilkkachu Jan 10 '19 at 22:39
  • @ilkkachu - it is a wildcard. I am moving multiple files at a time to a folder and then I have to zip them up, but I wont know the entire name because of the wildcard. I wish I knew how to post my entire script here. do you know how I can do that? – Scott Mick Jan 10 '19 at 22:50
  • @DopeGhoti, [[ -f *.foo ]] tests to see if there's a file literally called *.foo. It doesn't work to find a.foo or b.foo. – ilkkachu Jan 11 '19 at 11:29
  • Incorrect; see the output of touch test.foo, [[ -f *.foo ]] && echo yep. – DopeGhoti Jan 11 '19 at 15:31

4 Answers4

0

So I have simplified it a bit for you.

#!/bin/bash

shopt -s nullglob
files=(yourdir/*)

if [[ ${#files[@]} == 0 ]]  # If array is equal to 0
  then echo "No files there" >&2
  exit 1
else
  gzip "${files[@]}" # gzip all elements within the array.
fi
shopt -u nullglob 

Explanation what the script does:

Setting nullglob by shopt -s nullglob

nullglob is used to count the files that match the pattern. Without nullglob the glob * would expand to a literal * meaning that the count will always be > 1 in an empty directory, resulting in an erroneous count.

Unsetting nullglob by shopt -u nullglob

This is importand if we have more code after this line that could be affected by nullglob.

  • 3
    might be more pertinent to the OP to use their glob ESGSN_*.SMS.EDR – Jeff Schaller Jan 10 '19 at 21:13
  • why not just if [[ -f /path/to/ESGSN_*.SMS.EDR ]]? – DopeGhoti Jan 10 '19 at 21:15
  • Why not just gzip /path/to/ESGSN_*.SMS.EDR? ... and then possibly redirect stderr to /dev/null? – Kusalananda Jan 10 '19 at 21:16
  • Just following the logic of the OP. This can of course be done with a one liner. I'm just trying to introduce new features he could use a lot of which are well documented here: https://mywiki.wooledge.org/glob and here https://mywiki.wooledge.org/BashFAQ/004 – Valentin Bajrami Jan 10 '19 at 21:22
  • The "if [[ -f &FILE_MASK_2# ]]; then" did not work. just skipped the files. I tried to shorten the script for all here because there is more to it. After I see that there are files to process I first gzip them and then I tar them. If the tar file already exist then I have logic that just adds any new zip files to the tar file. I am just trying to get around the fact that if there are no files in any particular run then the script just ends normally without an error. But the fact that I am using a wildcard to see if there are files is not letting me just skip quietly until the next run. – Scott Mick Jan 10 '19 at 21:43
  • Here is my entire script, if interested.. um, well I cant add it here. nvermind – Scott Mick Jan 10 '19 at 21:46
  • 1
    @ValentinBajrami, this answer would be much better if it did include some explanation of what it does. – ilkkachu Jan 10 '19 at 22:39
  • @ilkkachu Thanks for comment. I added some explanation to the best of my ability and hope this makes sense. Mostly quoted mywiki.wooledge.org/glob – Valentin Bajrami Jan 11 '19 at 09:28
0
if ! gzip ESGSN_*.SMS.EDR 2>/dev/null; then
    printf 'No files to process (gzip exit code: %d)\n' "$?"
fi

Your test will always be true as the string ESGSN_*.SMS.EDR is non-empty. The * glob will not be processed when it's in double quotes.

Also, most shells will by default retain the pattern unexpanded if it doesn't match anything, which in your case means that your code would end up creating an empty file called ESGSN_*.SMS.EDR.gz if the pattern doesn't match any filenames.

The code above will simply try to compress all files that match the pattern, and if it fails it prints a message.

Kusalananda
  • 333,661
0

There are two ways to answer this: fix your current script, or propose an alternative which will be faster and more precise. I'll attempt both :)

First of all, a problem with your script the way it is, is that [ "ESGN_*.SMS.EDR" ] will always evaluate as true. The [ "<string>" ] construct simply tests whether the string is non-empty. Even when there are no files, the string you've given is non-empty, therefore the test is not doing anything.

What you would need to do to fix it is to loop over all files and test whether they match the pattern. The following works for me:

for F in *; do
    if [[ "$F" =~ ESGSN_.*\.SMS\.EDR ]]; then
        printf "Processing '%s'\n" "$F"
        gzip < "$F" > "$F.gz"
    fi
done

However, that's not how I would really do it, if I wanted to solve this problem for my own use. Instead it is faster and more natural to use GNU find, which easily does pattern-matching:

find ./ -type f -regex ".*/ESGSN_.*\.SMS\.EDR" -exec bash -c "gzip < {} > {}.gz" \;

The find command is very powerful and if you're going to be using Linux a lot you will wish to make yourself familiar with it. I recommend having a look through man find.

Kusalananda
  • 333,661
cryptarch
  • 1,270
0

Thanks everyone. I was able to get what I needed from:

if ls -lrt ESGSN_*.SMS.EDR ; then
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
  • If you're going to do that, you probably don't care to see the output from ls, so you could use ls ESGSN_*.SMS.EDR >/dev/null 2>&1 to get rid of the possible listing and the possible error messages. Also -lrt are not necessary either. – ilkkachu Jan 11 '19 at 11:34