32

Input:

ARCHIVE  B1_NAME  B2_NAME  B3_NAME  ELEMENT  INFO_NAM WERT PROCID
-------- -------- -------- -------- -------- -------- ---- ------
15MinAvg AIRSS    33-GIS   DMDMGIS1 I        MvAvr15m 1123  CP
15MinAvg AIRSS    33-GIS   DMDMGIS1 P        MvAvr15m 2344  CP
15MinAvg AIRSS    33-GIS   DMDMGIS1 Q        MvAvr15m 4545  CP
15MinAvg AIRSS    33-GIS   DMDMGIS2 I        MvAvr15m 6576  CP
15MinAvg AIRSS    33-GIS   DMDMGIS2 P        MvAvr15m 4355  CP
15MinAvg AIRSS    33-GIS   DMDMGIS2 Q        MvAvr15m 6664  CP

Output:

ARCHIVE  B1_NAME  B2_NAME  B3_NAME  ELEMENT WERT
-------- -------- -------- -------- ------- ----
15MinAvg AIRSS    33-GIS   DMDMGIS1 I       1123
15MinAvg AIRSS    33-GIS   DMDMGIS1 P       2344
15MinAvg AIRSS    33-GIS   DMDMGIS1 Q       4545
15MinAvg AIRSS    33-GIS   DMDMGIS2 I       6576
15MinAvg AIRSS    33-GIS   DMDMGIS2 P       4355
15MinAvg AIRSS    33-GIS   DMDMGIS2 Q       6664

I want to delete the two columns INFO_NAM and PROCID from my input file.

3
  • 1
    Which two columns do you really want to be removed. Your output has INFO_NAM & PROCID deleted
    – neuron
    Commented Aug 9, 2015 at 16:02
  • awk '{$(NF-1)=$(NF-2)=""};1' <file | column -t can format it nicely.
    – cuonglm
    Commented Aug 11, 2015 at 2:50
  • Related: "Does the inverse of cut exist?" unix.stackexchange.com/q/89869/323093
    – enharmonic
    Commented Nov 22, 2021 at 22:13

5 Answers 5

53

If you are content to clear the columns rather than completely removing them:

Don't print 6th and 8th column

awk '{$6=$8=""; print $0}' file
1
  • 2
    This doesn't work in cases where the delimiter is something besides space; it makes the contents of the field the empty string, but does not remove the field altogether. See echo "a|b|c|d|e" | awk -v FS='|' -v OFS='|' '{$2=$4=""; print}' yields a||c||e
    – enharmonic
    Commented Oct 21, 2020 at 22:22
34

This has been answered before elsewhere on Stack Overflow:

I believe awk is the best for that.

awk '{print $1,$2,$3,$4,$5,$7}' file

It is possible to use cut as well.

cut -f1,2,3,4,5,7 file
7
  • 8
    just to mention it: the --complement option for cut might be handy in here, i.e. removing two fields rather than selecting six: cut -f6,8 --complement file
    – FelixJN
    Commented Aug 10, 2015 at 7:53
  • awk is working...... but whats happening... the format is changed.... its just taking the field but not the exact structure... and cut is not working... @AndreiR
    – Nainita
    Commented Aug 10, 2015 at 15:20
  • I have tried this, cut –c1-45,55-58. But before executing this I have to count the total characters then only I can us this. But I wanted to print the columns with the same as my input format
    – Nainita
    Commented Aug 10, 2015 at 15:25
  • @Nainita maybe you have different separator that is not space. In awk you should specify it (i.e. using -F "\t" if tabular). Using cut, it is necessary to use -d (cut -d, if using comma).
    – AndreiR
    Commented Aug 10, 2015 at 15:25
  • @AndreiR cut -f1 file doesn't work. see this image
    – alhelal
    Commented Oct 23, 2017 at 16:35
16

The best way to delete columns is with cut:

cut --complement -d' ' -f6,8 file

Explanation:

  • -d specifies the delimiter; in this case, a space
  • --complement keeps the columns other than the ones specified in -f
  • -f specifies the columns to cut (rather than the columns to keep, since --complement is being used); in this case, columns 6 and 8

From the cut man page:

  -d, --delimiter=DELIM
        use DELIM instead of TAB for field delimiter

  -f, --fields=LIST
         select only these fields;  also print any line that contains
         no delimiter character, unless the -s option is specified

  --complement
         complement the set of selected bytes, characters or fields

Some others have proposed using a construction like awk '{$2=$4=""; print $0}', but this doesn't work in cases where the delimiter is something besides space; it makes the contents of the field the empty string, but does not remove the field altogether. For example, echo "a|b|c|d|e" | awk -v FS='|' -v OFS='|' '{$2=$4=""; print}' yields a||c||e.

4
  • 2
    MacOS aka BSD doesn't seem to have --compliement
    – Rick
    Commented Jul 16, 2021 at 7:13
  • @Rick see stackoverflow.com/questions/45851402/… for workaround using brew install coreutils and gcut in terminal.
    – enharmonic
    Commented Jul 20, 2021 at 22:46
  • Ok thanks I will take a look
    – Rick
    Commented Jul 21, 2021 at 3:41
  • Works for me on macOS 10.14.6 with homebrew coreutils. Commented Sep 23, 2021 at 1:58
3

Use printf to preserve the format of each field. Each field is x characters long and the minus sign justifies the string left.

awk '{ printf("%-8s %-8s %-8s %-8s %-8s %-4s\n", $1, $2, $3, $4, $5, $7)}' file
2

If you're open to a Perl solution...

perl -ane 'printf("%-8s %-8s %-8s %-8s %-8s %-4s\n", $F[0], $F[1], $F[2], $F[3], $F[4], $F[6])' file

These command-line options are used:

  • -n loop around every line of the input file, do not automatically print every line

  • -a autosplit mode – split input lines into the @F array. Defaults to splitting on whitespace

  • -e execute the following perl code

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .