0

I am running a gpg --verify on a list of files that I am referencing from gpg_verify.txt. I want to track which passed, so that I can later download some files that have first passed my check.

Therefore, how can I capture whether/or not a particular file in my loop passed/failed so that I can log it into a different file, that I can later reference?

I want something like:

while read -r line;
do 
  gpg --verify $line
  if(above output^ passes) then;
   > passed_gpg.txt
  else
   > failed_gpg.txt
done < gpg_verify.txt

Here is example output when I just run:

while read -r line;
do 
  gpg --verify $line
done < gpg_verify.txt

Output:

gpg: Signature made Tue Feb 11 17:26:10 2020 UTC
gpg:                using RSA key XXXXXXXXXXXX
gpg: Good signature from "Rando person (XXXXX Signing Key) <example@example.com>" [ultimate]
swarr35
  • 89
  • 1
  • 8
  • Try `if [ gpg --verify "test" >/dev/null 2>&1 ]; then echo "success"; else echo "failure"; fi` – Wolfgang Brehm Feb 12 '20 at 23:07
  • @WolfgangBrehm, what is the `[` for there? `[` is an alias for the command named `test`, it's not part of `if` syntax. – Charles Duffy Feb 12 '20 at 23:12
  • 1
    ...which is to say, this would properly be `if gpg --verify "$line"; then ...`, no `[` needed. – Charles Duffy Feb 12 '20 at 23:13
  • 1
    @swarr35, ...that said, it's generally a bad idea to use line-oriented text files to store filenames in the first place. It's perfectly legal for a filename to contain a newline -- someone can run `mv somefile.gpg badfile.gpg$'\n'somefile.gpg`, but you don't want your code writing `badfile.gpg` to `passed_gpg.txt` when that name didn't actually succeed. The only character it's completely safe to use to separate filenames (or environment variable definitions, or command-line arguments, or arbitrary C strings) is the NUL, since that's the only character that can't exist in a C string at all. – Charles Duffy Feb 12 '20 at 23:15

1 Answers1

1

Consider:

#!/usr/bin/env bash
while IFS= read -r filename; do
  if gpg -v "$filename"; then
    printf '%s\n' "$filename" >&3
  else
    printf '%s\n' "$filename" >&4
  fi
done <gpg_verify.txt 3>passed_gpg.txt 4>failed_gpg.txt

What's different here?

  • We're putting the command whose exit status we want to test inside the if.
  • We're explicitly writing something to the output files, not just opening them.
  • We're opening each output file only once, when the loop starts (and then attaching them to distinct file descriptor numbers). That means that outfile isn't truncated every time we want to write to it.

This still isn't perfect -- a better tool would probably avoid making the assumptions about filenames implicit in storing them in a line-oriented file -- but it's a place to start.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441