项目作者: adsr303

项目描述 :
Make it easier to use Python as an AWK replacement.
高级语言: Python
项目地址: git://github.com/adsr303/awking.git
创建时间: 2018-08-25T20:54:57Z
项目社区:https://github.com/adsr303/awking

开源协议:MIT License

下载


awking

Make it easier to use Python as an AWK replacement.

Basic usage

Extracting groups of lines

  1. from awking import RangeGrouper
  2. lines = '''
  3. text 1
  4. text 2
  5. group start 1
  6. text 3
  7. group end 1
  8. text 4
  9. group start 2
  10. text 5
  11. group end 2
  12. text 6
  13. '''.splitlines()
  14. for group in RangeGrouper('start', 'end', lines):
  15. print(list(group))

This will output:

  1. ['group start 1', 'text 3', 'group end 1']
  2. ['group start 2', 'text 5', 'group end 2']

Extracting fixed-width fields

  1. from awking import records
  2. ps_aux = '''
  3. USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
  4. root 1 0.0 0.0 51120 2796 ? Ss Dec22 0:09 /usr/lib/systemd/systemd --system --deserialize 22
  5. root 2 0.0 0.0 0 0 ? S Dec22 0:00 [kthreadd]
  6. root 3 0.0 0.0 0 0 ? S Dec22 0:04 [ksoftirqd/0]
  7. root 5 0.0 0.0 0 0 ? S< Dec22 0:00 [kworker/0:0H]
  8. root 7 0.0 0.0 0 0 ? S Dec22 0:15 [migration/0]
  9. root 8 0.0 0.0 0 0 ? S Dec22 0:00 [rcu_bh]
  10. root 9 0.0 0.0 0 0 ? S Dec22 2:47 [rcu_sched]
  11. saml 3015 0.0 0.0 117756 596 pts/2 Ss Dec22 0:00 bash
  12. saml 3093 0.9 4.1 1539436 330796 ? Sl Dec22 70:16 /usr/lib64/thunderbird/thunderbird
  13. saml 3873 0.0 0.1 1482432 8628 ? Sl Dec22 0:02 gvim -f
  14. root 5675 0.0 0.0 124096 412 ? Ss Dec22 0:02 /usr/sbin/crond -n
  15. root 5777 0.0 0.0 51132 1068 ? Ss Dec22 0:08 /usr/sbin/wpa_supplicant -u -f /var/log/wpa_supplica
  16. saml 5987 0.7 1.5 1237740 119876 ? Sl Dec26 14:05 /opt/google/chrome/chrome --type=renderer --lang=en-
  17. root 6115 0.0 0.0 0 0 ? S Dec27 0:06 [kworker/0:2]
  18. '''
  19. for user, _, command in records(ps_aux.splitlines(), widths=[7, 58, ...]):
  20. print(user, command)

This will output:

  1. USER COMMAND
  2. root /usr/lib/systemd/systemd --system --deserialize 22
  3. root [kthreadd]
  4. root [ksoftirqd/0]
  5. root [kworker/0:0H]
  6. root [migration/0]
  7. root [rcu_bh]
  8. root [rcu_sched]
  9. saml bash
  10. saml /usr/lib64/thunderbird/thunderbird
  11. saml gvim -f
  12. root /usr/sbin/crond -n
  13. root /usr/sbin/wpa_supplicant -u -f /var/log/wpa_supplica
  14. saml /opt/google/chrome/chrome --type=renderer --lang=en-
  15. root [kworker/0:2]

The problem

Did you ever have to scan a log file for XMLs? How hard was it for you to
extract a set of multi-line XMLs into separate files?

You can use re.findall or re.finditer but you need to read the entire log
file into a string first. You can also use an AWK script like this one:

  1. #!/usr/bin/awk -f
  2. /^Payload: <([-_a-zA-Z0-9]+:)?Request/ {
  3. ofname = "request_" (++index) ".xml"
  4. sub(/^Payload: /, "")
  5. }
  6. /<([-_a-zA-Z0-9]+:)?Request/, /<\/([-_a-zA-Z0-9]+:)?Request/ {
  7. print > ofname
  8. }
  9. /<\/([-_a-zA-Z0-9]+:)?Request/ {
  10. if (ofname) {
  11. close(ofname)
  12. ofname = ""
  13. }
  14. }

This works, and quite well. (Despite this being a Python module I encourage you
to learn AWK if you don’t already know it.)

But what if you want to build this kind of stuff into your Python application?
What if your input is not lines in a file but a different type of objects?

Python equivalent using awking

The RangeGrouper class groups elements from the input iterable based on
predicates for the start and end element. This is a bit like Perl’s range
operator or AWK’s range pattern, except that your ranges get grouped into
START..END iterables.

An equivalent of the above AWK script might look like this:

  1. from awking import RangeGrouper
  2. import re
  3. import sys
  4. g = RangeGrouper(r'^Payload: <([-_a-zA-Z0-9]+:)?Request',
  5. r'</([-_a-zA-Z0-9]+:)?Request', sys.stdin)
  6. for index, request in enumerate(g, 1):
  7. with open(f'request_{index}.xml', 'w') as f:
  8. for line in request:
  9. line = re.sub(r'^Payload: ', '', line) # Not optimal
  10. print(line, file=f, end='')

The predicates may be regular expressions, either as re.compile() objects or
strings; or they may be any callables that accept a single argument and return
a true/false value.

Caveats

The grouping algorithm reads the input iterable lazily. You can still run out
of memory if you keep references to previous groups without consuming them.