Awk: `Begin { ` Part 1
jemma.dev
jemma.dev
Csv is not standardized and the quoting rules are weird (and not standardized).
If you can live with a certain amount of loss of fidelity in your output, you can get away with using awk. If you want a coarse prototype, use awk.
If you need robust, production-grade handling of csv files, use (or write) something else.
Csv files are a little bit like like dates: superficially simple, with lots of corner cases. Largely for the same reason: lack of standardization.
That said, awk is awesome. It's small enough to fit in your brain, unlike Perl (maybe yours is larger than mine?). It's also pretty universally available, with few massive incompatibilities between versions, unlike shell (provided you avoid the gawk-specific features). I love it.
"Csv files are a little bit like like dates: superficially simple, with lots of corner cases. Largely for the same reason: lack of standardization."
CSV files, depending on who generates them, are a bit like dates if the status of a year as leap or not depended on whether the date of Easter were 0 mod 4.
I'm torn. On one hand, it's easy. It lets people work with the data, albeit using error-prone tools like NotePad++ and Excel.
On the other hand, it's just flat out lazy to use.
For example, if I schedule an event for Oct 1-Jan 1 right now, the most likely (least surprising) parse would be Oct 1, 2021 through January 1, 2022. Which is both surprising because parsing Oct 1 depends on the current date, and because the parsing of Jan 1 depends on the parse of Oct 1, and because both of these depend on the fact that you're scheduling (in all likelihood) a future event, rather than describing a past event. So whatever date parser you use (no matter how good it is at handling different notations) will return garbage if it doesn't take all these into account.
Even worse (well, maybe similar, but more surprising): imagine if on Feb 28, you parse "Feb 29-Mar 1"... both of those dates could land in an entirely different year than "Feb 28-Mar 1" would, depending on whether the current year is a leap year...
I dare say I have not yet seen a single parser in my life that handles such issues. In fact I don't think I've seen a parser that can parse a date interval, or that can even do "parse this string assuming it is after that date", or anything like that.
And all of these problems are before we even consider time zones, leap seconds, daylight savings, syntactic ambiguities, etc... not just how they affect individual dates, but also ordered dates (/intervals) like above...
You can google "nlp date extraction" maybe? I've used libraries in the past that do this.
Note: they're far from being perfect. I ended up not using any, as each had their weird corner cases.
Here's an old one: http://natty.joestelmach.com/try.jsp#
I tried with: "first week of december to end of january"
And it gave me: Tue Dec 01 15:31:30 UTC 2020 Fri Jan 31 15:31:30 UTC 2020
Edit: this one seems more polished: http://nlp.stanford.edu:8080/sutime/process
If your CSV file contains any field entered by humans AWK isn't going to be powerful enough to parse it at scale. Someone somewhere is going to have the name 'Mbat"a, Sho,dlo' in some bizarre ass romanization (and this assume you're not accepting Unicode, which is a whole other can of worms that AWK is not prepared to deal with) that breaks your parser.
'Mbaät\"a, Sho,dló'
"a" followed by "ä" because some suggest encoding umlauts as double characters. When you decode that does it go first or second?
Answer: use Unicode.
Throw an escape character in there, before the quote character just to make it interesting.
This is a good time for everyone to review: https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-...
Most CSV files do not follow this standard of course. But you could normalize all CSV files to RFC4180 (or any other consistent format) as the first step of your processing pipeline.
I worked on a team that used CSV somewhat extensively. For the data we generated, it was RFC complaint. It's pretty trivial to get RFC-compliant CSVs, too; most languages have a library — ours was in the standard library, too.
We also had a ("terrible", as we joked) idea to create a subset of CSV that would contain typing information in a required header row. (We never did it, and it is a bad idea.)
> If you are consuming CSV files in the wild, you can be sure that whoever is supplying them to you is using horrible tools to create them and will be unwilling or unable to address issues you find in them.
…but this is absolutely true. We also consumed CSVs from external sources and contractors, and this was an absolute drain on our productivity. I've also worked with engineers of this caliber, and changing CSV wouldn't change the terrible output. I've seen folks approach eMail, HTTP with a cavalier "oh, it's a trivial text format, I don't need a library!" attitude, and inevitably get it wrong. Pointing out the flaws in their implementation and that a library would fulfill their use-case just fine is just met with more hacks (not fixes) to try to further munge the output into shape. It is decidedly not software engineering. I've seen this even with JSON.
But yeah, even with RFC standard CSV, you shouldn't be parsing it with awk. It is the wrong tool.
csvkit [0] might be that tool; I discovered it after my last painful encounter with CSV files and haven't used it in anger yet. Among other things, it translates CSV to JSON, so you can compose it with jq.
[0] https://github.com/Chris00/ocaml-csv [1] https://colin.maudry.com/csvtool-manual-page/ [2] https://github.com/gpvos/csved/blob/master/csved
There's also `xsv`, from the author of `ripgrep`: https://github.com/BurntSushi/xsv
[0]: https://bitbucket.org/rbr/csvtools
[1]: https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text
[2]: https://www.gnu.org/software/gawk/manual/html_node/awk-split...
[3]: https://www.gnu.org/software/gawk/manual/html_node/Field-Sep...
Oh, sh*t. I will look for something else.
https://miller.readthedocs.io/en/latest/10min.html
It so much faster than csvkit
Something that will show a table, with a single pixel border between cells, that allows searching for a value, copying a cell?
For instance, consider a project that I'm currently working on. Google Docs sheet exported to CSV. The file documents dozens of servers used as load balancers, websites, and database servers. The files has gone from MS Excel to Google Docs, and been maintained by four admins over 12 years. There are no columns per se, rather "sections of rows", each of which isn't even consistent in itself. One section is double columned, with the top row listing public IP address, login name, etc and the second row listing LAN IP address, login password, etc.
sqlite is useless on these files and frankly I've seen these things more often than well-formatted spreadsheets at every company I've ever worked with. Nobody but software developers treat spreadsheet columns as database fields.
1. IPython with Pandas if I expect to do any in-depth exploration/manipulation of the data.
2. A short Python script like `python -c 'import csv, sys; r = csv.reader(sys.stdin); ...' <data.csv` if it needs to run on someone else's machine.
3. https://github.com/BurntSushi/xsv if I want to quickly munge some data or extract a field.
4. Gnumeric if I want a GUI.
5. https://github.com/andmarti1424/sc-im if I want a TUI. This is closest to what you were asking for.
> 5. https://github.com/andmarti1424/sc-im if I want
> a TUI. This is closest to what you were asking for.
Thank you! Yes, this seems to be almost perfect. I cannot believe that there is no "arbitrary string search" feature, but I can grep in another terminal window at least.Thank you.
I need to browse the cells in a something like curses.
csvlook -I | less -S
or
csvformat -T | less -S
(-I to avoid mixed data-types being displayed weird, but I don't consistently use that)from csvkit - https://csvkit.readthedocs.io/en/1.0.2/scripts/csvlook.html
Tons of useful CSV tools in there - csvcut, csvjoin, csvgrep.
csvformat -T
Makes most CSV much more manageable for a shell pipeline, as tabs are easy to deal with and unlikely to be in the actual dataThere are a few CLI applications for working with data stored in a CSV file, so long as the data is formed as a database: each row as a data entry, each column as a database field. The single CLI app that run on Linux for browsing a spreadsheet that is not formed as a database, SC-IM, does not support searching for arbitrary text!
Therefore I am writing osheet: A Linux CLI app for browsing a spreadsheet. It currently supports only XLS files, because that is what I need. It currently crashes a lot. It currently has no features other than searching. It won't even scroll yet to display all the rows and columns. I just banged it out last night when I should have been sleeping. But I'm working on it, you are invited to test it, report bugs, and pull requests are of course welcome. It's written in Python and Curses.
What I came here to say is that when I have a csv file I'm looking at with awk, thos first thing I do is a `wc -l`, then get NF (number of fields) for the first row of the csv (here e.g. 80), followed by `awk -F, 'NF==80'` | wc -l`. If the numbers don't match, then I know it's not parsing properly.
The most common issue of course is commas in quotes strings. I have a small script that removes these, so I can still use awk easily. Anything more complex like newlines in quotes strings and maybe it's time to question if awk is still worth it.
https://github.com/Nomarian/Awk-Batteries/blob/master/Units/...
gawk -f $AWK/Units/csv.awk -e '{print NF}'
https://blog.kowalczyk.info/article/fc9203f7c72a4532b1ae51d0...
People are careless when writing CSV files because they think it is simple: just put a comma between columns, right?
Funny thing was, a lot of the product names contained an ampersand (no problem there). But one product had an html entity encoded ampersand (&). I have no idea how that semicolon escaped, eh, escaping - but that one line suddenly had most of the columns off by one...
I can see how the entity got into the db (probably errant cutnpaste) - but I wonder at the csv writer that gleefully copied the extra separator to the csv export...
$ ruby -rcsv -ne 'puts $_.parse_csv[1]' education.csv
Enrolment in primary, secondary and tertiary education levels
Total, all countries or areas
AWK is a nice little language. Perl is all of it and shell, sed, grep. I am not proficient in Perl but I know some Ruby $ ruby -rEnglish -ne 'puts $_ if $NR <= 5' education.csv
$ ruby -rEnglish -aF, -ne 'puts $F[1] if $NR <= 5' education.csv
$ ruby -rEnglish -ne 'END { puts $NR }' education.csv
$ ruby -rEnglish -ne 'puts $_ if $NR % 500 == 0' education.csv
Module English provides AWK names $ perl -MEnglish -ne 'print if $NR < 5' education.csv
https://ruby-doc.org/stdlib-2.3.0/libdoc/English/rdoc/Englis...My first big kid job was taking over ownership of a Perl-based Oracle-backed data warehouse. Mostly it was SQL queries wrapped up with a Perl script executed by cron that output excel workbooks or csvs and emailed or dumped to a file server.
Most of the pivots and reporting tables were actually generated in Perl because it was just nicer to work with than Excel.
It was wonderful, I learned so much, mostly how to love Perl and CPAN.
We merged our telco billing system with our new parent company with some Perl, cron, a couple SQL queries and an FTP server.
I have said it for years and I will continue to repeat. If you could snap your fingers and delete all the Perl code in the world your lights would turn off.
JSON data files seem to be a similar deal. Sometimes they are actually properly formed JSON arrays and sometimes they are individual line-delimited objects.
Data files are a mess, is there a command line tool that is well suited to taking in many inconsistent formats and outputting something ergonomic?
There is almost always some normalisation ("scrubbing") needed to prep a CSV. But CSV is viable and awk can rip through massive amounts of data. It is a brilliant and powerful tool.
> It's small enough to fit in your brain, unlike Perl
Perl is also brilliant and powerful. Setting aside the bigotry of people who dislike sigils and using braces for scope, many people who fail to learn Perl well have not tried to use Perl-OOP objects as primitives. Once you do this, Perl's versatility and speed are hard to beat.
For example analysing the number of people per-year over multiple differently formatted files is as easy as `mlr uniq -f pid,year then count -g year`. It has filtering, very extensive manipulation capabilities and a nice documentation.
John has also reacted very fast on feature requests I had (so fast that I've not yet implemented using them).
Making this reproducable and usable for multiple people has always been an annoyance in semi-ad-hoc data collection.
-v FPAT='[^,]*|"[^"]+"'
instead of BEGIN { FPAT = "[^,]*|\"[^\"]+\"" }
>If you get the awk programming language manual…you’ll read it in about two hours and then you’re done. That’s it. You know all of awk.I can't work my head around this quote. That's a ridiculous claim. Even for a experienced programmer, learning a new programming language in 2 weeks, let alone 2 hours would be nothing short of a miracle. I've been using awk for past 2-3 years or so and I wrote a book on GNU awk one-liners earlier this year (https://learnbyexample.github.io/learn_gnuawk/). I'm nowhere close to knowing all of awk
not to criticise your work, but this does not sit well with me.
And yeah, it's possible to start using basic field processing and regexp features (if you already know it) in 2 hours and learn most of it in 2 weeks. But, that quote could've been something like you could get started in 2 hours instead of saying one could know all of awk.
That quote is definitely ridiculous. He may have been referring to just chapter 2, in which the "whole language" is outlined. But later chapters also take time, there even is an exercise about writing an assembler in AWK as well as implementing multiple algorithms.
Some stuff was already somewhat familiar to me from studying/practicing C earlier this year.
Overall a 10/10 book so far, but takes time and patience for sure!
Surely handling the intricacies of CSV can be a pain, but let's face it: Most tasks are simple and its results are easily verified for correctness. Obviously, I don't write my production webserver with AWK -- I write simple script to parse data (locally), find semantic issues in CSV files, analyze log data, etc..
AWK is great! If you want a slightly bigger cheatsheet, here's mine: https://github.com/rethab/awk-scripts/blob/master/talk.txt
Because I won't know ahead of time what all the interesting values or summaries will be, but if I know I can get it through AWK it will be cheap to extract or compute those values and summaries later, once I know what they are.
It's hyperlinked to the Gawk manual, but it seems likely he actually meant A, W & K's The Awk Programming Language (1988), which you could conceivably read in 2 hours, as it's a joy to read. I used it and The C Programming Language as exemplars of great documentation when writing my own.
It is freely available at archive.org: https://archive.org/details/pdfy-MgN0H1joIoDVoIC7
Although this is like 1,000th article on how easy it is to learn awk. Why write yet another one?
Awk in 20 Minutes (2015) https://news.ycombinator.com/item?id=23048054
Learn just a little Awk (2010) https://news.ycombinator.com/item?id=17322412
Learn Awk by Example (2019) https://news.ycombinator.com/item?id=22455779
it goes on and on...
I had not seen the others so this is an intro to awk for me. But in general if something has made it to the front page of HN it was interesting enough for enough people to put it there.
Awk for me is part of the layers of tools from grep/sed -> AWK -> perl one liner -> full on script. The further down the ladder you go, the more restricted you are, but this means that programs are terser and usually stay readable despite the terseness.
I would also recommend Perl One liners [1] which did the same thing for me for Perl one liners and, subsequently, full Perl.
20 minutes for that tutorial is enough to write non-trivial awk programs, and, least or most importantly, impress colleagues.
https://gist.github.com/jaysoffian/7bb70e1065f085b46a00
You never know when a bit of awk will save your bacon.