Py1
Py1, a Python AWK #
One should use the right tool for the right task. But Learning 300 tools is counterproductive, so one needs a fallback. To be generic enough that fallback must be scriptable. So we have AWK, Perl, Sed, TCL… and their read-only languages.
Enters py1, my new project. It’s a “Python AWK”.
You can use it to write Python one-liners. Just use {{
and }}
instead of
identation, ;
instead of line feed:
py1 "for x in range(4): {{ print x; print x*2 }}"
You promised AWK #
In most case you want to start with something, do something for each line, then conclude. py1 provides a template for AWK-like usage.
py1 --begin 'count=0' --each-line "if 'cow' in L: count += 1" --end 'P(count)'
To ease hacking, py1 provides you a set of 1&2-letters variables and functions.
In the example above we have L
, the current line. We also have P()
, an alias
for print()
. They can be overriden, for examples lines are read from F
:
py1 -b 'F=zip(open("file1"), open("file2")' -b 'count=0' -l "if 'cow' in L: count += 1" -e 'P(count)'
Nothing magic, they’re just Python variables.
Sustainable scripting #
If you find yourself writing a longer than readable snippet, you can transform it in regular Python code than can easily be refactored for later reuse.
If your 1 liner becomes 500 character long, turn it into a Python module and keep the code flowing!
py1 -b 'count=0' -l "if 'cow' in L: count += 1" -e 'P(count)' --dump-code
Gives you:
## Program conveniency variables.
ENV=os.environ # ENV: dict of Environment strings
# Input
F = sys.stdin # F: input File, defaults to stdin
WS = None # WS: Word Separator, defaults to whitespace
WRE = None # WS: Word RegExp separator, overrides WS if set
# Output
OF = sys.stdout # OF: Output File, defaults to stdin
OWS = None # OWS: Output Word Separator, defaults to whitespace
OLS = None # OLS: Output Line Separator, defaults to \n
def P(*args, **kwargs):
"""Like print() but honors OWS, OLS & OF."""
kwargs.setdefault("sep", OWS)
kwargs.setdefault("end", OLS)
kwargs.setdefault("file", OF)
print(*args, **kwargs)
def M(pattern, string=None, flags=0):
"""Returns all capture groups starting with the full match."""
string = R if string is None else string
matched = re.search(pattern, string, flags)
if matched is None:
return None
return (matched.group(0), ) + matched.groups()
def S(pattern, repl, string=None, count=0, flags=0):
"""Substitute pattern with repl in string (or R if string is None)."""
string = R if string is None else string
return re.sub(pattern, repl, string, count, flags)
## --begin
count =0
## Main loop
# LN: Line Number; R: Raw Line
for LN, R in enumerate(F):
## Line conveniency variables.
L = R.strip() # L: Line without whitespace arround.
if WRE is None:
W = L.split(WS) # W: Words split on WS
else:
W = re.split(WRE, L) # W: Words split on WRE
NW = len(W) # Number of words
## --each-line
if 'cow'in L :count +=1
## --end
print count
I want it! #
pip install py1
The documentation is here, the code on github.