FILE1=$1
FILE2=$2
if [ ! -e "$FILE2" ]
then
touch $FILE2
fi
while read line; do
if grep -q "$line" $FILE2
then
echo
else
echo $line >> $FILE2
fi
done < $FILE1
I want to add the lines of FILE1 to FILE2 if they are not present in FILE2. My purpose is to list FILE1's lines, and add them to FILE2 if the lines are not present in FILE2.
What's wrong?
Best Answer
That assumes that the file names don't contain
=
characters. If they might, on systems that support /dev/fd/n, you could do:Note that if lines occur several times in
$file1
and not in$file2
, all occurrences will be appended to$file2
. If that's not what you want, then:If the lines are unique and you don't mind the output being sorted, you could also do:
As to what's wrong in your code:
all uppercase variables are by convention reserved for environment variables (variables exported to the environment which is a shared namespace), so it's good practice not to use all uppercase variables for mere shell variables.
You quoted it in the arguments to
[
, but not totouch
, why?Also, note it's
If you want the variable to always be treated as a file argument, you need:
Also the
if ! condition; then do-something-to-make-it-true
are often bad practice and subject to race condition. It's better to doenforce-the-condition || die-if-couldn't
. So here:But anyway, the
>>
redirection will create the file (and return an error if it can't).When you start using loops in shells especially
while read
loops, then that generally means you're going for the wrong approach. You're going to run several commands sequentially for each line of a file, which is not how you do shell scripting. Instead, you want to run a few specialised commands once cooperating to the task.First, to read a
line
in POSIX shells, the syntax isnot
read lineAgain, it's:
Or:
Or:
If you want to search for strings instead of matching regexps, you need the
-F
option and if you want to match lines as a whole, you need-x
. So:Again, you're applying the split+glob operator to the content of
$line
(and to$FILE2
if usingbash
not in sh mode).Also,
echo
can't be used for arbitrary data. You need:Here. But it's a waste to re-open
$file2
for each pass in the loop where you could have done it once for the whole loop.Again:
if using
bash
.