While awk
doesn't have a function to actually delete a field from a line, you can set particular column(s) to the empty string.
However, there is a common trick which can be used to delete columns (e.g. columns 5 and 7):
awk '{$5=$7="" ; $0=$0;$1=$1}1'
The $0=$0;$1=1
sets $0 to itself and $1 to itself. This has the side-effect of removing any extra field delimiters (i.e. the delimiters that would otherwise exist immediately after the now-empty fields $5 and $7)
NOTE: this will also convert all the field separators in $0 to whatever the Output Field Separator (OFS) is currently set to (e.g. with default FS and OFS, it will convert multiple tabs and spaces between fields to a single space)
With perl
, it's much easier. It does have a function (splice()
) to delete columns from an array:
perl -lane 'BEGIN{$,=" "}; splice(@F,4,1); splice(@F,5,1); print @F'
$,=" "
sets the output field separator to a single space.
Notes:
perl arrays start from 0, not 1. so @F[4]
is the fifth column.
this deletes column 5, so the second column (7th) we want to delete is now the 6th column, which is why the second splice
deletes @F[5]
.
To avoid any potential confusion here, delete the columns in reverse order:
perl -lane 'BEGIN{$,=" "}; splice(@F,6,1); splice(@F,4,1); print @F'
or you can use a loop:
perl -lane 'BEGIN{$,=" "}; foreach $c (7,5) {splice(@F,$c-1,1)}; print @F'
BTW, if you only want to delete the first or the last column, you can use shift @F
, or pop @F
.
Output:
with the following input:
1 2 3 4 5 6 7 8 9 10
10 9 8 7 6 5 4 3 2 1
a b c d e f h i j k
All of the above scripts will produce the following output:
1 2 3 4 6 8 9 10
10 9 8 7 5 3 2 1
a b c d f i j k
cut
at least, there is a--complement
optioncut
is very useful but has the extremely annoying limitation that it can only handle single-character field delimiters (this is why I usually reach forawk
orperl
without even consideringcut
).cut
really needs the ability to handle regexp delimiters. The--complement
option is a very nice new feature.