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 wheel
And 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 wheel
print $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 --upgrade
grep -v pip
removespip
from the results (-v
,--invert-match
select 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 1
I get the 1st column from the output which is the package name. The default delimiter forcut
I 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
3
You transform it to:
$ other-command 1 2 3
In 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 }'
6
echo -e
means enable interpretation of backslash escapes, if you don’t use it, it will print:
$ echo '3\n6\n1'
3\n6\n1
Use 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 wheel
In 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 3
I’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