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
如果 FILE2 中不存在 FILE1 的行,我想将它们添加到 FILE2 中。我的目的是列出 FILE1 的行,如果 FILE2 中不存在这些行,则将它们添加到 FILE2 中。
怎么了?
答案1
awk 'NR == FNR {first[$0];next}; ! ($0 in first)' "$file2" "$file1" >> "$file2"
假设文件名不包含=
字符。如果可以的话,在支持 /dev/fd/n 的系统上,您可以这样做:
awk 'NR == FNR {first[$0];next}; ! ($0 in first)' \
/dev/fd/3 3< "$file2" /dev/fd/4 4< "$file1" >> "$file2"
请注意,如果行在 中多次出现$file1
且不在 中出现$file2
,则所有出现的情况都将附加到 中$file2
。如果这不是您想要的,那么:
awk 'NR != FNR && ! ($0 in seen); {seen[$0]}' \
/dev/fd/3 3< "$file2" /dev/fd/4 4< "$file1" >> "$file2"
如果这些行是唯一的并且您不介意输出被排序,您也可以这样做:
LC_ALL=C sort -uo "$file2" "$file1" "$file2"
至于你的代码有什么问题:
FILE1=$1 FILE2=$2
按照惯例,所有大写变量均保留用于环境变量(导出到作为共享命名空间的环境的变量),因此最好不要将所有大写变量仅用于 shell 变量。
if [ ! -e "$FILE2" ] then touch $FILE2 fi
你在 的参数中引用了它[
,但没有在 的参数中引用它touch
,为什么?
另外,请注意它是
touch "$file_or_option"
如果您希望变量始终被视为文件参数,您需要:
touch -- "$file2"
而且它们if ! condition; then do-something-to-make-it-true
通常是不好的练习并且受到比赛条件的影响。最好这样做enforce-the-condition || die-if-couldn't
。所以在这里:
touch -- "$file2" || exit
但无论如何,>>
重定向将创建该文件(如果不能,则返回错误)。
while read line; do
当您开始在 shell 中使用循环时特别是while read
循环,那么这通常意味着您采用了错误的方法。您将为文件的每一行顺序运行多个命令,这不是 shell 脚本编写的方式。相反,您想运行一次一些专门的命令合作到任务。
首先,要在 POSIX shell 中读取 a line
,语法是
IFS= read -r line
不是
read line
if grep -q "$line" $FILE2
再说一次,它是:
grep -q "$option_or_regexp"
或者:
grep -q -- "$regexp"
或者:
grep -qe "$regexp"
如果您想搜索字符串而不是匹配正则表达式,则需要该-F
选项,如果您想匹配整个行,则需要-x
.所以:
grep -qxFe "$line" < "$file2"
then echo else echo $line >> $FILE2
同样,您将 split+glob 运算符应用于 的内容$line
(如果不在 sh 模式下$FILE2
使用,则应用于bash
)。
此外,echo
不能用于任意数据。你需要:
printf '%s\n' "$line" >> "$file2"
这里。但是,为循环中的每次传递重新打开是一种浪费,$file2
而您本来可以在整个循环中完成一次。
fi done < $FILE1
再次:
done < "$file1"
如果使用bash
.