Get specific rows from a file
I wanted to update some python dependencies with pip, and I got this output when I run pip list --outdated:
$ pip list --outdated
Package Version Latest Type
---------- ------- ------ -----
fonttools 4.33.3 4.40.0 wheel
pip 22.1 23.1.2 wheel
setuptools 58.1.0 68.0.0 wheelAnd I thought: “Hm, it would be nice if I could print from the 3rd line and below, I don’t want the table header and separator in my output. This way, I can grab the package names with ease”.
You can print specific lines with awk and the NR built-in variable. NR contains the row number (aka line), which is an index that starts from 1:
$ pip list --outdated |
awk '{ if (NR > 2) print $0 }'
fonttools 4.33.3 4.40.0 wheel
pip 22.1 23.1.2 wheel
setuptools 58.1.0 68.0.0 wheelprint $0 means print all the fields (columns) in the row. $1 refers to the first field, $2 to the second, and so on. awk is build for that kind of stuff.
And the complete command, where I upgrade the dependencies (use it at you own risk, check first which dependencies you really want to upgrade!):
$ pip list --outdated |
awk '{ if (NR > 2) print $0 }' |
grep -v pip |
cut --delimiter ' ' --field 1 |
xargs pip install --upgradegrep -v pipremovespipfrom the results (-v,--invert-matchselect non-matching lines) because I didn’t want to upgrade pip this way (I got an error when I didERROR: To modify pip, please run the following command:..).- With
cut --delimiter ' ' --field 1I get the 1st column from the output which is the package name. The default delimiter forcutI believe is the tab character, that’s why I use a space as a delimiter. - With
command | xargs other-command, if the command output is, for example:
# output of "command"
1
2
3You transform it to:
$ other-command 1 2 3In other words, you pass each line from the output of the previous command as a positional argument to the next command (the one that xargs calls), and execute the next command (other-command in this example).
And if you want only a specific row, for example the 2nd row:
$ echo -e '3\n6\n1' | awk '{ if (NR == 2) print $0 }'
6echo -e means enable interpretation of backslash escapes, if you don’t use it, it will print:
$ echo '3\n6\n1'
3\n6\n1Use the paste command if you’re feeling adventurous
A less robust way would be to use the paste command with the --serial option and then the cut command:
# doesn't work pip list -o, only with echo for some reason
# probably pip list -o has some funny characters?
$ echo 'Package Version Latest Type
---------- ------- ------ -----
fonttools 4.33.3 4.40.0 wheel
pip 22.1 23.1.2 wheel
setuptools 58.1.0 68.0.0 wheel' |
paste --serial --delimiters '*' |
cut -d '*' -f 3- |
tr '*' '\n'
# result
fonttools 4.33.3 4.40.0 wheel
pip 22.1 23.1.2 wheel
setuptools 58.1.0 68.0.0 wheelIn the example above, I print the text directly into the console with echo because pip list --outdated doesn’t really work here with this method, for some reason I don’t care to investigate.
To understand how paste works, see a note of mine on how to split even and odd lines into two columns with paste.
cut -f 3- means get from the 3 column until the last column (see man cut for more stuff the -f option can do). And, if you want a specific row, for example the 3rd:
$ pip list -o |
paste --serial --delimiters '*' |
cut -d '*' -f 3I’m using ’*’ as delimiter; find a char that is not part of your data/output/files.
Links
Other things to read
Popular
- Reveal animations on scroll with react-spring
- Gatsby background image example
- Extremely fast loading with Gatsby and self-hosted fonts