2012-09-24 52 views
0

所有,我试图运行一个sed命令从特定文件中去除卡号。我试图以单线形式做到这一点,我认为一切进展顺利 - 但我意识到,如果我的第一个替代品不符合该模式,它会继续执行下一个命令。如果没有匹配,是否有办法让它退出?Sed - 如果模式不匹配,停止多部分命令?

我们的系统中有16-22个长度的卡号,所以我在考虑这个时考虑了可变长度。我的规格是保留任何16位数字的前6位和后4位,并在中间保留ax(星号)。

sed 'h;s/[0-9]\{6\}\([0-9]\{5\}\)\([0-9]*\)[0-9]\{4\}/\1\2/;s/./*/g;x;s/\([0-9]\{6\}\)[0-9]*\([0-9]\{4\}\)/\1\2/;G;s/\n//;s/\([0-9]\{6\}\)\([0-9]\{4\}\)\(.*\)/\1\3\2/' 

的问题在于,如果命令的这部分事实:

s/[0-9]\{6\}\([0-9]\{5\}\)\([0-9]*\)[0-9]\{4\}/\1\2/ 

觉得没有什么,模式空间依然输入。它继续进入下一个命令,然后用星号代替所有的东西。我最终得到的是输入后跟着相同数量的星号(如果它不符合我的第一个替代品中的“卡号资格”)。如果它什么被认为是一个可能的卡号,它是完美的。

任何想法?

+0

什么是卡号?信用卡号? – tripleee

+1

当需要sed中的if/unless'成语时,我发现'/ pattern/{s // replacement /; ....}或否定的'/ pattern /!{...}'可能非常有用。 – potong

回答

2

但我意识到,如果我的第一个替代品不符合该模式,它会继续到下一个命令中 。有没有办法让它退出,如果 没有匹配?

您可以使用分支命令。我添加到位评价他们:

sed ' 
    h; 
    s/[0-9]\{6\}\([0-9]\{5\}\)\([0-9]*\)[0-9]\{4\}/\1\2/; 

    ## If last substitution command succeeds, go to label "a". 
    t a 
    ## Begin next cycle (previous substitution command didn't succeed). 
    b 
    ## Label "a". 
    :a 

    s/./*/g; 
    x; 
    s/\([0-9]\{6\}\)[0-9]*\([0-9]\{4\}\)/\1\2/; 
    G; 
    s/\n//; 
    s/\([0-9]\{6\}\)\([0-9]\{4\}\)\(.*\)/\1\3\2/ 
' 

UPDATE由于意见。

所以要变换

texttexttext111111222223333texttexttext 

texttexttext111111*****3333texttexttext 

尝试:

echo "texttexttext111111222223333texttexttext" | 
sed -e ' 
    ## Add newlines characters between the characters to substitute with "*". 
    s/\([0-9]\{6\}\)\([0-9]\{5\}\)\([0-9]*\)\([0-9]\{4\}\)/\1\n\2\3\n\4/; 
    ## Label "a". 
    :a; 
    ## Substitute first not-asterisk character between newlines with "*". 
    s/\(\n\**\)[^\n]\(.*\n\)/\1*\2/; 
    ## If character before second newline is not an asterisk, repeat 
    ## the substitution from label "a". 
    /^.*\*\n/! ta; 
    ## Remove artificial newlines. 
    s/\n//g 
    ## Implicit print. 
' 

输出:

texttexttext111111*****3333texttexttext 
+0

+1,Bravo!我真的认为对sed 1-liner的渴望往往是错误的方法;-)。 – shellter

+0

谢谢!这工作得很好。不过,我确实发现了一个新问题,而不是在OP中。假设我有一个如下所示的订单项:texttexttext11111222223333texttexttext - 此脚本的目标是返回该确切的行,仅用2代替*。在我的第一个替换命令中,我遇到了一个问题,因为它正在按照它的说法进行操作,而仅替换我的数字部分(但仍包括数字外部的文本)作为我的返回值以进行星号标记。有没有一种方法的s命令可以只返回替代模式,并省略该行的其余部分? – user1695263

+0

@ user1695263:我不完全了解你。你想用'*'替换所有'2'并删除所有其他字符吗?那么你以前的例子会在'*****'中产生,不是吗? – Birei

1

man sed

t label 
     If a s/// has done a successful substitution since the last 
     input line was read and since the last t or T command, then 
     branch to label; if label is omitted, branch to end of script. 

T label 
     If no s/// has done a successful substitution since the last 
     input line was read and since the last t or T command, then 
     branch to label; if label is omitted, branch to end of script. 
     This is a GNU extension. 

所以我认为你可以在你的第一个s命令后,只需添加T;