Hi,
i want to delete a column from a file. the file is like :
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0

if i want to remove any column the outout should be like ( suppose 4):
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0

i have used swk command, but its not giving the desired output: its giving some extra delimeters:

awk 'BEGIN{FS=OFS="|"}{$4="";gsub(FS,"")}1' file

please help

Dani AI

Generated

the issue with gsub(FS,"") is that it zaps every | in the record after you blank out a field, so the line gets rebuilt without proper separators. Instead of search/replace on the whole record, change the field array and let awk rebuild the line for you via OFS. showed one way; here is a compact variant that deletes a single column by shifting fields left and reducing NF (no extra or missing pipes):

awk -F'|' -v c=4 'BEGIN{OFS=FS}
{
  if (c>=1 && c<=NF) {
    for (i=c; i<NF; i++) $i = $(i+1)
    NF--
  }
  print
}' file

Need to drop several columns at once from the command line? Do it in one pass so indexes do not drift. Pass a comma-separated list and delete in descending order:

awk -F'|' -v cols='2,4,9' 'BEGIN{
  OFS=FS; n=split(cols,a,/,/)
  for(i=1;i<=n;i++) for(j=i+1;j<=n;j++) if(a[i]<a[j]) {t=a[i];a[i]=a[j];a[j]=t}
}{
  for(k=1;k<=n;k++){
    c=a[k]+0
    if (c>=1 && c<=NF) { for(i=c;i<NF;i++) $i=$(i+1); NF-- }
  }
  print
}' file

Shell tip for your loop: rather than rewriting the file repeatedly, collect all positions and run awk once; it is faster and avoids off-by-one math after each deletion. Also note ’s cut approach is great on GNU systems, but --complement is not available in BSD/BusyBox cut (e.g., macOS). In those cases, the awk methods above stay portable.

Recommended Answers

All 12 Replies

hi,

awk -F'|' '{
   for(n=1; n<=NF; n++){
      if(n!=NF)fmt="%s|"; else fmt="%s\n"
      if(n!=4)printf(fmt,$n)
   }
}' UrFile

I want to use it in a loop with taking input from the user ,
i tried to place a loop but its not working.

how is it not working?

please show what you want, and what you've tried.

     while [ "$*" != " " ]
        do
        awk -v awk_var=$1  -F'|' '{
           for(n=1; n<=NF; n++){
              if(n!=NF)fmt="%s|"; else fmt="%s\n"
              if(n!= awk_var)printf(fmt,$n)
           }
        }' new

        echo "$1 Column deleted"
        shift

     done

i used this code.. but its going to a infinite loop, i want to use command line arguments as input

while [ -n "$1" ]
do
   ...
   shift
done

or

for arg #in "$@" is not needed
do
   ...
done
while [ -n "$1" ]
do
awk -F'|' -v awk_var=$awkvar '{
   for(n=1; n<=NF; n++){
      if(n!=NF)
         fmt="%s|";
      else
        fmt="%s\n";
      if(n!=awk_var)printf(fmt,$n)
   }
}' new > new.new

mv new.new new

echo "$1 Column deleted"
shift
((awkvar=$1-1))
done
awk -F'|' -v awk_var=$awkvar '{
for(n=1; n<=NF; n++){
if(n!=NF)
fmt="%s|";
else
fmt="%s\n";
if(n!=awk_var)printf(fmt,$n)
}
}' new 

can u please explain the above code

there is not much to explain :( the code is quite simple.

what don't you understand?

fmt and NF, m not familiar with adv awk commands.

fmt is a user defined variable; I put the format to be used according to current field is the last field or not.
NF is an awk variable, it's "The number of fields in the current input record." (so says gawk's man page)

ok.. i get it now.. thanks a lot :)

There is no need to use awk to solve this. A short but easy-to-understand solution with cut:

$ cat a 
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0
1|2|3|4|5|6|7|8|9|0

$ cut -d'|' -f4 --complement a
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0
1|2|3|5|6|7|8|9|0
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.