13

I want to delete the 5th word of each line in a file.

The current content of the file:

File is not updated or and will be removed  
System will shut down f within 10 seconds  
Please save your work 55 or copy to other location  
Kindly cooperate with us D  

Expected output:

File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us
31

How about cut :

$ cut -d' ' -f1-4,6- file.txt 
File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us
  • -d' ' sets the delimiter as space

  • -f1-4,6- selects the first to 4th field (word), leaving the 5th one and then continue printing from 6th to the rest.

11

A solution with cut:

cut -d ' ' -f1-4 -f6- FILE
  • Multiple -f is not supported in my cut (GNU) at least.. – heemayl Jul 14 '15 at 15:54
  • Supported in BSD cut but I like your response better than mine. – fd0 Jul 14 '15 at 15:56
  • 1
    If it's GNU cut, you get the --complement flag to simplify things: cut --complement -d ' ' -f5. Remember to redirect the output to a new file, then mv it over the original. – Toby Speight Jul 15 '15 at 10:30
6

awk: remove the 5th field

awk '{for (i=5; i<NF; i++) $i = $(i+1); NF--};1' file

If you want to save the file in-place: https://stackoverflow.com/q/16529716/7552

You could just erase the contents of the 5th field, but that leaves 2 consecutive output field separators:

awk '{$5 = ""};1' file
  • the caveat here is that changing any field's value in awk has the side effect of rewriting the whole "$0" with only 1 separator between each fields. should be taken into account if you wanted to keep any alignment (unless gnu awk has an option avoiding this? regular awk/nawk will recompute $0) – Olivier Dulac Jul 15 '15 at 0:57
  • In both case you reformat the line with a single separator. If there is 2 space or space +tab in a separator, the result is a single space in place. This is hoppefully OK for most of the text. – NeronLeVelu Jul 16 '15 at 9:02
4

With POSIX sed:

sed -e 's/[^[:alnum:]_][[:alnum:]_][[:alnum:]_]*//4' <file
  • why limit the class to :alnum: and _ and not anything else then :blank: or :space: ? – NeronLeVelu Jul 16 '15 at 9:03
  • @NeronLeVelu: That's depend on how you define what make a word. – cuonglm Jul 16 '15 at 9:22
  • @mikeserv; Nice catch! I updated my answer. – cuonglm Jul 16 '15 at 16:46
  • What's the \( capture group \) for? – mikeserv Jul 16 '15 at 16:55
  • @mikeserv: my mis-typing, I have just tried some ways to retain the delimiter. – cuonglm Jul 16 '15 at 17:00
2

glenn offered a solution that is equivalent to

awk '{$5=""; print}' file

As he and others have pointed out, this

  1. strips leading and trailing whitespace from every line,
  2. compresses each string of whitespace (spaces and/or tabs) into a single space, and
  3. leaves two spaces between the fourth and six words.

A hack to fix the third problem is

awk '{$5=""; print}' file | sed 's/  / /'

This will still leave one or more added space(s) at the end of any line that had five or fewer words going in.  If you can identify a word that will never appear in the input,

awk '{$5="unicorn"; print}' file | sed 's/ *unicorn//'

will handle even that (but it still leaves problems 1 and 2).

2
 sed 's/^\(\([[:blank:]]*[^[:blank:]]\{1,\}\)\{4\}\)[[:blank:]]*[^[:blank:]]*/\1/' YourFile > Output.txt
  • posix sed based on space/tab separator (meta class [:blank:]])
  • keep the following space after 5th word but removing the one before

A more robust (sed take the longest pattern possible and pattern with * could miss separation or word in first version) but a bit longer version

sed 's/^\([[:blank:]]*\([^[:blank:]]\{1,\}[[:blank:]]\{1,\}\)\{4\}\[^[:blank:]]\{1,\}/\1/' YourFile > Output.txt
  • 1
    sed 's/[^[:blank:]]*//5' – mikeserv Jul 16 '15 at 9:09
  • @mikeserv, this will keep both surrounding separator, sed 's/[[:blank:]*[^[:blank:]]*//5' is better. Very good point. I suspected that sed take each single char as a entity but it take greatest unbreaked pattern as entity – NeronLeVelu Jul 16 '15 at 11:08
  • sed 's/[[:blank:]][^[:blank:]]*//4' will remove the 5th field entirely. – mikeserv Jul 16 '15 at 13:20
  • @mikeserv Assuming there is not starting space on the line (like in the sample) – NeronLeVelu Jul 17 '15 at 7:25
  • In this case, yes, I think you're right. Usually such a thing would be a null field and the behavior would be correct. In this case you should do as @cuonglm did and ensure you reference a word each time like sed 's/[[:blank:]][^[:blank:]][^[:blank:]]*//4', or, w/ GNU/BSD/toybox seds: sed -E 's/[[:blank:]][^[:blank:]]+//4'. – mikeserv Jul 17 '15 at 7:41
1

Perl.

perl -ne 'print $_ =~ /^(\w+ +\w+ +\w+ +\w+ +)\w+ (.*)/,"\n"' file
1

Another possibility, assuming GNU cut:

cut -d' ' -f5 --complement file.txt
-1

Using Perl > 5.10 (and successfully outputting all lines :0) ):-

perl -nE '/^((\w+ +){4})\w+ *(.*)/; say $1.$3' file

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.