1

I want to delete a specific strings from file. I try to use:

for line3 in $(cat 2.txt)
do
   if grep -Fxq $line3 4.txt
      then
      sed -i /$line3/d 4.txt
   fi
done

I want this code to delete lines from 4.txt if they are also in 2.txt, but this loop deletes all lines from 4.txt and I have no idea why. Can someone tell what is wrong with this code ?

2.txt:

a
ab
abc

4.txt:

a
abc
abcdef
2
  • Can you show some sample data from 2.txt and 4.txt Commented Oct 27, 2014 at 20:10
  • Only sed! sed $( sed 's,^, -e /^,;s,$,$/d,' 2.txt ) 4.txt Commented Oct 27, 2014 at 20:48

4 Answers 4

1

You can do this via single awk command:

awk 'ARGV[1] == FILENAME && FNR==NR {a[$1];next} !($1 in a)' 2.txt 4.txt
abcdef

To store output back to 4.txt use:

awk 'ARGV[1] == FILENAME && FNR==NR {a[$1];next} !($1 in a)' 2.txt 4.txt > _tmp && mv _tmp 4.txt

PS: Added ARGV[1] == FILENAME && to take care of empty file case as noted by @pjh below.

Sign up to request clarification or add additional context in comments.

1 Comment

This does not work if the first file is empty: it generates no output but it should copy all lines from the second file. See the 'Caveat' in 10 Awk Tips, Tricks and Pitfalls for details of the problem, and how to fix it.
1
grep -F -v -x -f 2.txt 4.txt 

or

grep -Fvxf 2.txt 4.txt

or

fgrep -vxf 2.txt 4.txt

Comments

0

Using just Bash (4) builtins:

declare -A found
while IFS= read -r line || [[ $line ]] ; do found[$line]=1 ; done <2.txt
while IFS= read -r line || [[ $line ]] ; do
    (( ${found[$line]-0} )) || printf '%s\n' "$line"
done <4.txt

The '[[ $line ]]' tests are to handle files with unterminated last lines.

Use 'printf' instead of 'echo' in case any of the output lines begin with 'echo' options.

Comments

0

Look ma', only sed...

sed $( sed 's,^, -e /^,;s,$,$/d,' 2.txt ) 4.txt
  1. Transform each line in 2.txt in a sed command, e.g., abc -> -e /^abc$/d
  2. Give the list of sed commands to an instance of sed operating on 4.txt

To store output back to 4.txt use:

sed -i $( sed 's,^, -e /^,;s,$,$/d,' 2.txt ) 4.txt

edit: while I love my answer on an aesthetic base, please don't try this at home! see pjh comment below for a detailed rationale of the many ways in which my microscript may fail

2 Comments

This solution has many problems. It fails if the first file is empty, or contains spaces, or contains slashes. It may generate the wrong output if the first file contains regular expression metacharacters. If the first file is very large it could cause the command to fail due to being too long. Also if the first file is very large it is likely to be grossly inefficient.
@pjh I edited my answer to put in evidence your comment. I confess that I posted this particular answer because of its beauty (as usual, beauty is in the eyes of the beholder!) rather than its usefulness...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.