{ "info": { "author": "Johan Nestaas", "author_email": "johannestaas@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Console", "Environment :: MacOS X", "Environment :: Win32 (MS Windows)", "Environment :: X11 Applications :: Qt", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python" ], "description": "red\n===\n\nPython regex command-line tool, to replace functionality akin to 'perl -ne'.\n\nInstallation\n------------\n\nFrom the project root directory::\n\n $ python setup.py install\n\nUsage\n-----\n\nUse --help/-h to view info on the arguments::\n\n $ red --help\n\nThe special variables available:\n\n:**line**:\n for the entire line that was matched, without the trailing newline\n:**g**:\n for groups, which you index to get that match group, as **g[0]** in \"(\\w+) .*\"\n:**ag**:\n for aggregated groups with the *-a* option, which is a list of all match groups\n:**d**:\n for the groupdict, which you can index by named group as **d[\"foo\"]** in \"(?P\\w+) .*\"\n:**ad**:\n for the aggregated group dicts, a list of dicts\n\nExample usage::\n\n $ cat test.txt \n foo 1 bar 2\n fiz 5 baz 10\n funk 10 bunk 9\n funk a bunk b\n a b c d\n aaaaa\n bbbb\n cc\n\nUse it like grep::\n\n $ cat test.txt | red \"\\w+ (\\d+) \\w+ (\\d+)\" \n foo 1 bar 2\n fiz 5 baz 10\n funk 10 bunk 9\n\nIt works with path as argument as well, *but the path must appear directly after the regex* (oddity of argparse).::\n \n $ red \"\\w+ (\\d+) \\w+ (\\d+)\" test.txt\n\nUse it to evaluate Python code on groups stored in variable **g**::\n\n $ red \"\\w+ (\\d+) \\w+ (\\d+)\" test.txt -e \"int(g[0]) + int(g[1])\"\n 3\n 15\n 19\n\nImport an arbitrary library and do absolutely anything::\n\n $ red '\\w+ (\\d+) \\w+ (\\d+)' test.txt -i json -e '\"{} => {}\".format(line, json.dumps(g))'\n foo 1 bar 2 => [\"1\", \"2\"]\n fiz 5 baz 10 => [\"5\", \"10\"]\n funk 10 bunk 9 => [\"10\", \"9\"]\n\nIf you want to execute a few python statements before the eval, you can do that as well with **-x**::\n\n $ red \"(\\w+) (\\d+).*\" test.txt -x 'x = int(g[1]) ; y = g[0][::-1]' -e '(x, y)'\n (1, 'oof')\n (5, 'zif')\n (10, 'knuf')\n\nUse it to aggregate across all of stdin, into list **ag**::\n\n $ cat test.txt | red \"\\w+ (\\d+) \\w+ (\\d+)\" -a \"sum([int(x[0]) for x in ag])\"\n 16\n\nAggregate has its own **-X** for an exec before the aggregate too::\n\n $ red \"(\\w+) (\\d+).*\" test.txt -X 's = sum(int(g[1]) for g in ag)' -a 's'\n 16\n\nEvaluate on each match, and aggregate against all matches::\n\n $ cat test.txt | red \"\\w+ (\\d+) \\w+ (\\d+)\" -a \"sum([int(x[0]) for x in ag])\" -e \"'adding {}'.format(g[0])\"\n adding 1\n adding 5\n adding 10\n 16\n\nYou can use named groups as well, stored in variables **d** and aggregated into **ad**::\n\n $ cat test.txt | red \"\\w+ (?P\\d+) \\w+ \\d+\" -e \"'first value is {first}'.format(**d)\"\n first value is 1\n first value is 5\n first value is 10\n\nEven multiline will work, since whatever is passed into **-x** is just **exec**'d::\n\n $ red '.*' test.txt -x '\n # if you want multiline, just hit apostrophe and press enter\n # and start typing\n if line.startswith(\"foo\"):\n print(\"Line started with foo: {}\".format(line))\n '\n\n Line started with foo: foo 1 bar 2\n\nGet creative!::\n\n $ cat urls.txt \n https://www.google.com/\n http://www.yahoo.com/\n http://www.example.com/foo\n\n $ red \"(.*)\" urls.txt -i requests -x 'response = requests.get(line)' -e '[response.status_code, response.content[:20]]'\n [404, '\\nERROR|INFO): \\S+ (?P.*)' -i requests,collections -x 'response = requests.get(d[\"url\"])' -e '(response.status_code, response.content[0:20])' -a 'collections.Counter([d[\"debuglevel\"] for d in ad]).items()'\n (404, '\\n