在bash中将包含特殊字符的变量传递给sed

在bash中将包含特殊字符的变量传递给sed,bash,sed,Bash,Sed,我需要从文件中删除子域: .domain.com .sub.domain.com -- this must be removed .domain.com.uk .sub2.domain.com.uk -- this must be removed 因此,我使用了sed: sed '/\.domain.com$/d' file sed '/\.domain.com.uk$/d' file 这一部分很简单,但当我尝试在循环中进行时,会出现以下问题: while read line do sed

我需要从文件中删除子域:

.domain.com
.sub.domain.com -- this must be removed
.domain.com.uk
.sub2.domain.com.uk -- this must be removed
因此,我使用了sed:

sed '/\.domain.com$/d' file
sed '/\.domain.com.uk$/d' file
这一部分很简单,但当我尝试在循环中进行时,会出现以下问题:

while read line
do
sed '/\$line$/d' filename > filename   
done < filename
读取行时
做
sed'/\$line$/d'文件名>文件名
完成<文件名

我想这是“.”和$的问题,我已经尝试了很多方法来摆脱它,但我现在已经没有主意了

您的循环有点混乱,因为您试图使用
sed
从文件中删除模式,但从同一文件中获取模式

如果您真的想从
filename
中删除子域,那么我想您需要以下内容:

#!/bin/bash

set -x 

cp domains domains.tmp

while read domain
do
  sed -r -e "/[[:alnum:]]+${domain//./\\.}$/d" domains.tmp > domains.tmp2
  cp domains.tmp2 domains.tmp
done < dom.txt 
cat dom.txt
是:

.domain.com
.sub.domain.com
.domain.co.uk
.sub2.domain.co.uk
sub.domain.co.uk
abc.yahoo.com
post.yahoo.com
.domain.com
.domain.co.uk
.yahoo.com
在这些输入上运行脚本会导致:

$ cat domains.tmp
.domain.com
.domain.co.uk
每次迭代将删除当前从
dom.txt
读取的
domain
的子域,并将其存储在临时文件中,该文件的内容将在下一次迭代中用于附加过滤


使用
set-x
尝试脚本很好,您会看到一些替换等。

您的循环有点混乱,因为您试图使用
sed
从文件中删除模式,但从同一文件中获取模式

sed -n 's/.*/²&³/;H
$ {x;s/$/\
/
: again
  s|\(\n\)²\([^³]*\)³\(.*\)\1²[^³]*\2³|\1\2\3|
  t again
  s/[²³]//g;s/.\(.*\)./\1/
  p
  }' YourFile
如果您真的想从
filename
中删除子域,那么我想您需要以下内容:

#!/bin/bash

set -x 

cp domains domains.tmp

while read domain
do
  sed -r -e "/[[:alnum:]]+${domain//./\\.}$/d" domains.tmp > domains.tmp2
  cp domains.tmp2 domains.tmp
done < dom.txt 
cat dom.txt
是:

.domain.com
.sub.domain.com
.domain.co.uk
.sub2.domain.co.uk
sub.domain.co.uk
abc.yahoo.com
post.yahoo.com
.domain.com
.domain.co.uk
.yahoo.com
在这些输入上运行脚本会导致:

$ cat domains.tmp
.domain.com
.domain.co.uk
每次迭代将删除当前从
dom.txt
读取的
domain
的子域,并将其存储在临时文件中,该文件的内容将在下一次迭代中用于附加过滤

使用
set-x
尝试脚本很好,您将看到一些替换,等等

sed -n 's/.*/²&³/;H
$ {x;s/$/\
/
: again
  s|\(\n\)²\([^³]*\)³\(.*\)\1²[^³]*\2³|\1\2\3|
  t again
  s/[²³]//g;s/.\(.*\)./\1/
  p
  }' YourFile
在工作缓冲区中加载文件,然后删除(迭代)以较早的行结尾的任何行,最后在结果之前。使用临时边缘分隔符比在模式中更易于管理\n

gnused的posix-e(从AIX测试)

在工作缓冲区中加载文件,然后删除(迭代)以较早的行结尾的任何行,最后在结果之前。使用临时边缘分隔符比在模式中更易于管理\n


--posix-e
用于GNU sed(在AIX上测试)

受NeronLeVelu想法启发的解决方案:

#!/bin/bash

#set -x

domains=($(rev domains | sort))

for i in `seq 0 ${#domains[@]}` ;do
    domain=${domains[$i]}
    [ -z "$domain" ] && continue
    for j in `seq $i ${#domains[@]}` ;do
        [[ ${domains[$j]} =~ $domain.+  ]] && domains[$j]=
    done
done


for i in `seq 0 ${#domains[@]}` ;do
    [ -n "${domains[$i]}" ] && echo ${domains[$i]} | rev >> result.txt
done
对于
cat域

.domain.com
.sub.domain.com
.domain.co.uk
.sub2.domain.co.uk
sub.domain.co.uk
abc.yahoo.com
post.yahoo.com
yahoo.com
您将获得
cat result.txt

.domain.co.uk
.domain.com
yahoo.com

受NeronLeVelu想法启发的解决方案:

#!/bin/bash

#set -x

domains=($(rev domains | sort))

for i in `seq 0 ${#domains[@]}` ;do
    domain=${domains[$i]}
    [ -z "$domain" ] && continue
    for j in `seq $i ${#domains[@]}` ;do
        [[ ${domains[$j]} =~ $domain.+  ]] && domains[$j]=
    done
done


for i in `seq 0 ${#domains[@]}` ;do
    [ -n "${domains[$i]}" ] && echo ${domains[$i]} | rev >> result.txt
done
对于
cat域

.domain.com
.sub.domain.com
.domain.co.uk
.sub2.domain.co.uk
sub.domain.co.uk
abc.yahoo.com
post.yahoo.com
yahoo.com
您将获得
cat result.txt

.domain.co.uk
.domain.com
yahoo.com


这也是错误的,您只需在第一次迭代中覆盖文件,所以我应该使用VARABLE将内容加载到其中,也许?在我看来,您首先应该更好地解释您试图实现的目标:)您从哪里获得要删除的模式?从档案中?您要从哪个文件中删除?来自同一个文件?听起来很奇怪。它是一个输入参数吗?输入参数是正则表达式吗?或者输入参数只是一个域,您想自动删除它的所有子域吗?这是我在上面推的一个文本文件。我需要删除此文件中域的所有子域。实际上,我是使用sed手动编写每个域来检查的:sed'/\.domain.com$/d'文件-现在我想在循环中执行此操作在这种情况下,为什么我的答案不是解决方案呢?:)我试图理解,但我不理解。对我来说,如果只需要排除子域,似乎不需要任何循环。特别是如果你有一个关于顶级域名的简短固定列表(例如only.com和.co.uk)。如果列表较长,您可能需要一个更复杂的解决方案。这也是错误的,您只需在第一次迭代中覆盖该文件。因此,我应该使用VARABLE将内容加载到其中,也许?在我看来,您首先应该更好地解释您试图实现的目标:)您从哪里获得要删除的模式?从档案中?您要从哪个文件中删除?来自同一个文件?听起来很奇怪。它是一个输入参数吗?输入参数是正则表达式吗?或者输入参数只是一个域,您想自动删除它的所有子域吗?这是我在上面推的一个文本文件。我需要删除此文件中域的所有子域。实际上,我是使用sed手动编写每个域来检查的:sed'/\.domain.com$/d'文件-现在我想在循环中执行此操作在这种情况下,为什么我的答案不是解决方案呢?:)我试图理解,但我不理解。对我来说,如果只需要排除子域,似乎不需要任何循环。特别是如果你有一个关于顶级域名的简短固定列表(例如only.com和.co.uk)。如果列表较长,您可能需要更复杂的解决方案。您的while循环已完全中断,您的
filename``位于三个不同的位置
sed`根据默认值对文件的每一行进行操作,甚至可以在使用
-i
标志时进行内联更改。问题是您正在截断传递给
sed
的文件。使用
-i
选项进行
sed
,或者将输出重定向到临时文件并将临时文件移回/while循环完全中断,您的
filename``位于三个不同的位置
sed`根据默认值对文件的每一行进行操作,甚至可以在使用
-i
标志时进行内联更改。问题是您正在截断传递给
sed
的文件。使用
sed
-i
选项,或将输出重定向到临时文件并将临时文件移回/检查格式;我不确定上标2和3应该代表什么字符。它们只是字符,在域名中不经常使用(直到最近),所以它们是完美的分隔符,但几乎可以使用任何字符。有了新的域名规则,其他的分隔符可能是必要的(或者至少在没有部分内容之前检查一下)啊,好吧,你故意添加它们,然后重新添加