Python in a fixlet is failing on using curly brackets

I’m trying to create/run a python script in a fixlet and for some reason it’s throwing an error trying to set counts = {}. Does Bigfix need some sort of escape for curly brackets to get past this step? The script runs fine on it’s own so I know its not a python error its something the fixlet doesn’t seem to like.

if {(name of (operating system) as string as lowercase contains "linux")}

//
//Deleting the append file
//
delete __appendfile

//
//Moving to file location and removing previous run
//
appendfile #!/bin/sh
appendfile cd /beanstore-client/dg/util
appendfile rm batchtable.py
appendfile rm batchdata.txt

//modify appendfile to allow execution
wait /bin/sh -c "chmod 555 {(client folder of current site as string) & "/__appendfile"}"

//execute shell script as written
wait "{(client folder of current site as string) & "/__appendfile"}"

//
// Batchtable.py starts after the following line
//
createfile until _EOF
#!/usr/bin/env python

import re
import glob
import sys

if len(sys.argv) > 1:
  logfiles = sys.argv[1:]
else:
  logfiles = glob.glob("/beanstore/PosErrlogs/retailErrlog*")

re_batch = re.compile("^(?P<log_date>....-..-..) ..:..:..,.........: INFO  : \[TillReceiver\] com\.pcmsgroup\.v21\.dfm\.tillreceiver\.TillReceiverSupportImpl: TillReceiverSupport Status:.* Processed batch = .*[^0-9](?P<batch_year>20[0-9][0-9])(?P<batch_month>[0-9][0-9])(?P<batch_day>[0-9][0-9])([0-9]{6})?[^0-9]")

counts = {}

Yes, there are rules for escaping curly-brackets, otherwise ActionScript attempts to use those as a Relevance substitution. See Tip: Escaping curly brackets for substitutions in ActionScript for examples.

Great that worked Jason I appreciate the help. I have come upon a new issue now that I have the full script working. I am creating the python script and using an appendfile to run it and in that appendfile I am trying to output the run to a txt:

appendfile ./batchtable.py >> batchdata.txt

The issue I have is that the file is being created but it’s empty. Is there something special I have to do to actually capture the output of the run python script or do I have to create the file in the python rather than pushing the output to a file on the linux box?

What happens if you run the python command the same way from the command line, manually?

I’m not sure the context there - are you creating a second appendfile to launch the Python script? Is this second file going to be interpreted by bash, or /bin/sh, or ??

Otherwise, if this isn’t a second __appendfile, I think you should handle redirection on the wait command…

For context, this can definitely be handled to do output (or input) redirection, but often requires careful quoting so the redirection is handled at the correct level. I should be able to find a reference later, but if memory serves you should be able to do something like

wait /bin/sh -c " './my_launcher.sh' >> /tmp/my-output.txt"

So here’s the full script to show what I am trying to do. The idea is to create the python script, run it and send the output to a .txt file, delete the python script and then we have another tool to pull the text file out for analysis.

if {(name of (operating system) as string as lowercase contains "linux")}

//
//Deleting the append file
//
delete __appendfile

//
//Moving to file location and removing previous run
//
appendfile #!/bin/sh
appendfile cd /beanstore-client/dg/util
appendfile rm batchtable.py
appendfile cd /beanstore-client/dg/upload
appendfile rm batchdata.txt

//modify appendfile to allow execution
wait /bin/sh -c "chmod 555 {(client folder of current site as string) & "/__appendfile"}"

//execute shell script as written
wait "{(client folder of current site as string) & "/__appendfile"}"

//
// Batchtable.py starts after the following line
//
createfile until _EOF
#!/usr/bin/env python

import re
import glob
import sys

if len(sys.argv) > 1:
  logfiles = sys.argv[1:]
else:
  logfiles = glob.glob("/beanstore/PosErrlogs/retailErrlog*")

re_batch = re.compile("^(?P<log_date>....-..-..) ..:..:..,.........: INFO  : \[TillReceiver\] com\.pcmsgroup\.v21\.dfm\.tillreceiver\.TillReceiverSupportImpl: TillReceiverSupport Status:.* Processed batch = .*[^0-9](?P<batch_year>20[0-9][0-9])(?P<batch_month>[0-9][0-9])(?P<batch_day>[0-9][0-9])([0-9]{{6}})?[^0-9]")

counts = {{}}
log_dates = set()
batch_dates = set()

for filename in logfiles:
  f = open(filename)
  for line in f:
    matchobj = re_batch.match(line)
    if matchobj:
      d = matchobj.groupdict()
      log_date = d["log_date"]
      log_dates.add(log_date)
      batch_date = "%s-%s-%s" % (d["batch_year"], d["batch_month"], d["batch_day"])
      batch_dates.add(batch_date)
      key = log_date,batch_date
      if key in counts:
        counts[key] += 1
      else:
        counts[key] = 1
  f.close()

log_dates = sorted(log_dates)
batch_dates = sorted(batch_dates,reverse=True)

for batch_date in batch_dates:
  line = batch_date
  for log_date in log_dates:
    key = log_date,batch_date
    if key in counts:
      count = counts[key]
    else:
      count = "-"
    line = line + "%7s" % (count,)
  line += "\n"
  sys.stdout.write(line)
log_dates_short = ["%s/%s" % (log_date[5:7],log_date[8:]) for log_date in log_dates]
log_dates_line = "            " + "  ".join(log_dates_short)
sys.stdout.write(log_dates_line + "\n")

_EOF
//Python program ends before the previous line

//Create a file with the Python program on the local filesystem
//
copy __createfile /beanstore-client/dg/util/batchtable.py

//Shell to Action Script Conversion Utility
delete __appendfile

appendfile #!/bin/sh
appendfile mkdir /beanstore-client/dg/upload
appendfile cd /beanstore-client/dg/util
appendfile chmod +x batchtable.py
appendfile cd /beanstore-client/dg/upload
appendfile ./batchtable.py >> batchdata.txt
appendfile cd /beanstore-client/dg/util
appendfile rm batchtable.py

//modify appendfile to allow execution
wait /bin/sh -c "chmod 555 {(client folder of current site as string) & "/__appendfile"}"

//execute shell script as written
wait "{(client folder of current site as string) & "/__appendfile"}"

delete __appendfile

If I run it manually it works without issue. The one caveat is that I had to add extra {}'s around the curly brackets in the script to get it to run in bigfix. Not sure if that is causing issues.

It might be necessary to amend that to invoke the shell explicitly

wait /bin/sh -c "{(client folder of current site as string) & "/__appendfile"}"

In the Python script itself, if I’m reading the regular expression correctly, I think there is a small change needed to the curly-bracket escaping

Original:

re_batch = re.compile("^(?P<log_date>....-..-..) ..:..:..,.........: INFO  : \[TillReceiver\] com\.pcmsgroup\.v21\.dfm\.tillreceiver\.TillReceiverSupportImpl: TillReceiverSupport Status:.* Processed batch = .*[^0-9](?P<batch_year>20[0-9][0-9])(?P<batch_month>[0-9][0-9])(?P<batch_day>[0-9][0-9])([0-9]{{6}})?[^0-9]")

New:

re_batch = re.compile("^(?P<log_date>....-..-..) ..:..:..,.........: INFO  : \[TillReceiver\] com\.pcmsgroup\.v21\.dfm\.tillreceiver\.TillReceiverSupportImpl: TillReceiverSupport Status:.* Processed batch = .*[^0-9](?P<batch_year>20[0-9][0-9])(?P<batch_month>[0-9][0-9])(?P<batch_day>[0-9][0-9])([0-9]{{6})?[^0-9]")

For the curly-brackets around the 6, you need to double the open-curlies so a Relevance substition is not started, but you do not need to double the close-curly brackets. You would only double the close-curly-bracket if this was inside a substitution, and you needed to use } as a literal string without ending the substitution. So it should look like

{{6}
1 Like

This was the issue. Thanks Jason!

1 Like