Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Python script that runs one-liner python scripts similarly to how Perl runs them portions based on http://code.activestate.com/recipes/437932-pyline-a-grep-like-sed-like-command-line-tool/ (Graham Fawcett, Jacob Oscarson, Mark Eichin) interface inspired by Perl
#!/usr/bin/env python
"""
Python script that runs one-liner python scripts similarly to how Perl runs them
portions based on http://code.activestate.com/recipes/437932-pyline-a-grep-like-sed-like-command-line-tool/
(Graham Fawcett, Jacob Oscarson, Mark Eichin)
interface inspired by Perl
"""
"""
Copyright (C) 2010 Drew Gulino
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import sys
import re
import getopt
from getopt import GetoptError
import os
def usage(progname):
print "Usage: " + progname
version()
print """
./pyliner (options) "script"
-a enables auto-split of input into the F[] array.
-F specifies the characters to split on with the -a option (default=" ")
-p loops over and prints input.
-n loops over and does not print input.
-l strips newlines on input, and adds them on output
-M lets you specify module imports
-o print out parsed and indented script on multiple lines
-e (assumed - does nothing, added for Perl compatibility)
variables:
F[] = split input
line = current input line
NR = current input line number
functions:
I(x) = function returns F[x] cast to integer
F(x) = function returns F[x] cast to float
script:
newlines are specified with ";"
":" will start an indent for the following lines
"?;" will add a newline and dedent the following lines
"/;" will reset the indent the far left
"BEGIN:" starts the an initial script not run in the input loop
"END:" starts part of the script run after the input loop
"#/" ends both the "BEGIN:" and "END:" portions of the script
"""
#test.txt=
"""
10,test
1,rest
100,test
10,best
1000,we
1,see
"""
"""
cat test.txt | ./pyliner.py -F"," -lane 'BEGIN:sum=0#/if I(0) > 90:sum+=I(0) END:print sum#/'
1100
"""
"""
pyliner:
cat test.txt | ./pyliner.py -F"," -lane 'BEGIN:sum=0#/a=F(0);if a > 90:sum+=a END:print sum/NR#/'
183.333333333
perl:
cat test.txt | perl -F"," -lane 'BEGIN {$sum=0; } ;$sum=$sum+=@F[0] if @F[0]>90;END { print $sum/$.; }'
183.333333333333
"""
def version():
print "version: 1.0"
write = sys.stdout.write
def indent_script(script_lines):
#indent lines
indent = 0
next_indent = 0
script = []
for cmd in script_lines:
cmd = cmd.strip()
if cmd[-1]==(":"):
indent=indent+1
if cmd[-1]=="?":
cmd=cmd[0:-1]
indent=indent-1
if cmd[-1]=="/":
cmd=cmd[0:-1]
indent=0
cmd=("\t"*next_indent)+cmd
next_indent = indent
script.append(cmd)
script = '\n'.join(script)
return script
def split_script(cmd):
#split lines
cmd = cmd.replace("?;","?\n")
cmd = cmd.replace("/;","/\n")
cmd = cmd.replace(";","\n")
cmd = cmd.replace(":",":\n")
return cmd
def main(argv, stdout, environ):
progname = argv[0]
split_lines=False
FS = ' '
print_input = False
strip_newlines = False
no_print_input = False
output_script = False
F =[]
def I(x): return int(F[x])
def f(x): return float(F[x])
# parse options for module imports
try:
opts, args = getopt.getopt(sys.argv[1:], 'oaplneM:F:')
except GetoptError:
print "Invalid Option!"
usage(progname)
return
opts = dict(opts)
if '-M' in opts:
for imp in opts['-M'].split(','):
locals()[imp] = __import__(imp.strip())
if "-a" in opts:
split_lines = True
if '-F' in opts:
FS = opts['-F']
if "-p" in opts:
print_input = True
if "-l" in opts:
strip_newlines = True
if "-n" in opts:
no_print_input = True
if "-e" in opts:
pass
if "-o" in opts:
output_script = True
cmd = ' '.join(args)
if not cmd.strip():
cmd = 'line' # no-op
begin_cmd = ''
end_cmd = ''
if cmd.find("BEGIN:") >= 0:
start=cmd.find("BEGIN:")
end=cmd.find("#/")
begin_cmd=cmd[start+6:end]
cmd=cmd[end+2:]
if cmd.find("END:") >= 0:
start=cmd.find("END:")
end=cmd.find("#/")
end_cmd=cmd[start+4:end]
cmd=cmd[:start]
cmd = split_script(cmd)
script_lines = cmd.splitlines()
if len(begin_cmd) > 1:
begin_cmd = split_script(begin_cmd)
begin_lines = begin_cmd.splitlines()
begin_script = indent_script(begin_lines)
begin_codeobj = compile(begin_script, 'command', 'exec')
result = eval(begin_codeobj, globals(), locals())
if result is None or result is False:
result = ''
elif isinstance(result, list) or isinstance(result, tuple):
result = ' '.join(map(str, result))
else:
result = str(result)
write(result)
if len(end_cmd) > 1:
end_cmd = split_script(end_cmd)
end_lines = end_cmd.splitlines()
end_script = indent_script(end_lines)
end_codeobj = compile(end_script, 'command', 'exec')
script = indent_script(script_lines)
if output_script == True:
print "BEGIN:"
print begin_script
print
print script
print
print "END:"
print end_script
print
#compile script
codeobj = compile(script, 'command', 'exec')
if print_input or no_print_input:
for num, line in enumerate(sys.stdin):
#line = line[:-1]
NR = num + 1
if strip_newlines == True:
line = line.strip()
if print_input == True:
print(line)
if split_lines == True:
F = [w for w in line.split(FS) if len(w)]
result = eval(codeobj, globals(), locals())
if result is None or result is False:
continue
elif isinstance(result, list) or isinstance(result, tuple):
result = ' '.join(map(str, result))
else:
result = str(result)
write(result)
if strip_newlines == True:
write('\n')
else:
result = eval(codeobj, globals(), locals())
if len(end_cmd) > 1:
result = eval(end_codeobj, globals(), locals())
if result is None or result is False:
result = ''
elif isinstance(result, list) or isinstance(result, tuple):
result = ' '.join(map(str, result))
else:
result = str(result)
write(result)
if __name__ == "__main__":
main(sys.argv, sys.stdout, os.environ)
@ursetto

This comment has been minimized.

Copy link

commented Nov 11, 2013

Couple notes:
Code objects with 'exec' as the mode will always return None from eval(), so the loop will always 'continue'.
The -p option doesn't behave like perl as it just prints unmodified input prior to executing the code.
The -o option doesn't work unless you specify both a BEGIN and END block.

Neat idea overall, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.