I have a portion of the VoIPBL update script.

cat /tmp/voipbl.txt | awk '{ print "if [ ! -z \""$1"\" -a \""$1"\"  != \"#\" ]; then /usr/sbin/ipset  -A voipbl_temp \""$1"\" ;fi;"}'

It creates lines like this:

if [ ! -z "" -a ""  != "#" ]; then  /usr/sbin/ipset -A voipbl_temp "" ;fi; | sh

I understand the second part is adding a line from the file (IP) to an ipset, but what is the test condition doing? What does it mean when you have -z and -a in the same set of brackets? And what does the not equal to "#" part mean?

  • 1
    That's not really an awk command - it's a shell command that just happens to be constructed using awk. Refer to the shell manual or man test to see what the brackets (and the -a) mean. – steeldriver Jun 6 '19 at 17:04

It's reading presumably IPs from the /tmp/voipbl.txt file and then creating a shell if construct based on them. The $1 parameter from the awk script refers to the item in the first column on each line so the string in place of will be that value in each iteration.

if [ ! -z "" -a ""  != "#" ]; then

! -z "" - Is checking that "" is not null. -z checks if the string is zero but the ! negates that. This could and probably should be replaced with -n which just checks for not-null

"" != "#" - Is checking that "" is not equal to # which I guess is something that could appear in your file.

The -a operator means and. So it's checking that the string is not null AND that it does not equal #.

If these conditions are met, the following will be executed:

/usr/sbin/ipset -A voipbl_temp ""

To understand this better, try running the awk command on a file with the following contents:


If you now run your awk command on that file, you get:

$ awk '{ print "if [ ! -z \""$1"\" -a \""$1"\"  != \"#\" ]; then /usr/sbin/ipset  -A voipbl_temp \""$1"\" ;fi;"}' file
if [ ! -z "" -a ""  != "#" ]; then /usr/sbin/ipset  -A voipbl_temp "" ;fi;
if [ ! -z "" -a ""  != "#" ]; then /usr/sbin/ipset  -A voipbl_temp "" ;fi;
if [ ! -z "#" -a "#"  != "#" ]; then /usr/sbin/ipset  -A voipbl_temp "#" ;fi;

The tests ensure that the /usr/sbin/ipset will only be run on the first line, with and not on the other two.

  • Great explanation. It makes sense now. When I looked it up, I found that -a test can be a test for an existing file. That threw me off. So I guess that behavior is different when it's not a file name, and is just a string? Either way, thanks! – d10nte Jun 6 '19 at 17:45
  • @d10nte: Yes, most people prefer to instead do something like: [ ! -z "" ] && [ "" != "#" ]. Perhaps for that reason. – jesse_b Jun 6 '19 at 17:50
  • That would much clearer Jesse_b. I also agree with your comment on using "-n" rather than the other construct. Thanks for your help. – d10nte Jun 6 '19 at 18:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.