V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
ficenow
V2EX  ›  Linux

大家好,我有一个关于 sed 命令的问题想问大家^ ^

  •  
  •   ficenow · 2016 年 1 月 11 日 · 4580 次点击
    这是一个创建于 3675 天前的主题,其中的信息可能已经有所发展或是发生改变。

    是这样的,我想用 sed 删除匹配到的行的指定范围行,比如 sed -i '/rows/d' data 是删除所有匹配到的包含 rows 字符串的行,但是在这些匹配行中,我想保留第一行,删除第 2 行到最后一行,有人知道怎么做吗?先谢谢了^ ^

    52 条回复    2016-01-14 09:52:28 +08:00
    lululau
        1
    lululau  
       2016 年 1 月 11 日
    sed -i '/rows/q'
    ficenow
        2
    ficenow  
    OP
       2016 年 1 月 11 日
    @lululau 你这样只是保留了第一个 rows 匹配行以上的内容,以下的内容全被删除了。。。
    xuboying
        3
    xuboying  
       2016 年 1 月 11 日 via Android
    perl -ne 'if ($.>=2) {print unless /rows/} else {print}'
    ficenow
        4
    ficenow  
    OP
       2016 年 1 月 11 日
    @lululau 我只是想对匹配到的行做修改,不动文件里的其他行
    ficenow
        5
    ficenow  
    OP
       2016 年 1 月 11 日
    @xuboying perl ?我想用 sed 实现><
    ficenow
        6
    ficenow  
    OP
       2016 年 1 月 11 日
    补充一点,是影响匹配到的行,文件中的其他行不能动><
    xuboying
        7
    xuboying  
       2016 年 1 月 11 日 via Android
    @ficenow 为啥不用 perl ,有 sed 的地方就有 perl
    ficenow
        8
    ficenow  
    OP
       2016 年 1 月 11 日
    @xuboying 但是你这样把所有的包含 rows 字符串的行都删除了,我想保留第一个包含 rows 字符串的行
    hucsmn
        9
    hucsmn  
       2016 年 1 月 11 日
    perl -e '$n=0; while(<>) {print if ($_ =~ /b/ && !($n++))}
    hucsmn
        10
    hucsmn  
       2016 年 1 月 11 日
    上面写错= =, perl -e '$n=0; while(<>) {print if (!($_=~/rows/) || !($n++))}'
    AnyOfYou
        11
    AnyOfYou  
       2016 年 1 月 11 日
    有个思路,可以先去替换第一行的 rows 到某个特殊的内容(只找第一个),然后再去删除包含 rows 的所有行,最后再把第一行的那个特殊关键字替换回 rows 。
    ficenow
        12
    ficenow  
    OP
       2016 年 1 月 11 日
    @hucsmn 那个 rows 的匹配串在哪改呀~~
    xuboying
        13
    xuboying  
       2016 年 1 月 11 日 via Android
    @ficenow $.是第几行的意思啊
    ficenow
        14
    ficenow  
    OP
       2016 年 1 月 11 日
    @hucsmn 非常感谢你,你解决了我的问题^ ^
    ficenow
        15
    ficenow  
    OP
       2016 年 1 月 11 日
    @hucsmn 再打扰一下,如果要保留最后一行的呢?
    hucsmn
        16
    hucsmn  
       2016 年 1 月 11 日
    @ficenow 试试 tac|perl .....|tac 行吗
    ficenow
        17
    ficenow  
    OP
       2016 年 1 月 11 日
    @hucsmn tac|perl -e '$n=0; while(<>) {print if (!($_=~/rows/) || !($n++))}' data|tac > test
    这样吗?会卡住
    xuboying
        18
    xuboying  
       2016 年 1 月 11 日 via Android
    perl -e '@x = <>; print $x[0];for (@x[1..$#x-1]){print unless /rows/ };print $x[$#x]}
    ficenow
        19
    ficenow  
    OP
       2016 年 1 月 11 日
    @xuboying 你这个直接在命令后面加目标文件不行啊><
    ficenow
        20
    ficenow  
    OP
       2016 年 1 月 11 日
    @xuboying 把你那最后缺少的'补上也报错 syntax error at -e line 1, near "]}"
    xuboying
        21
    xuboying  
       2016 年 1 月 11 日 via Android
    哦,最后一花括号去掉换成单引号
    ficenow
        22
    ficenow  
    OP
       2016 年 1 月 11 日
    @xuboying 嗯,试了,但是所有的 rows 行都没有了>< 不是预期的效果
    xuboying
        23
    xuboying  
       2016 年 1 月 11 日 via Android
    @ficenow 怎么可能, print $x[0] print $x[$#x] 是分别打印第一和最后一行
    ficenow
        24
    ficenow  
    OP
       2016 年 1 月 11 日
    @xuboying 可是我重定向到文件里所受 rows 关键字搜索不到啊。。
    xuboying
        25
    xuboying  
       2016 年 1 月 11 日 via Android
    @ficenow 其掉 for 那段执行能得到第一和最后行吗?
    ficenow
        26
    ficenow  
    OP
       2016 年 1 月 11 日
    @xuboying 能,得到的是文件里的第一行和最后一行
    Earthman
        27
    Earthman  
       2016 年 1 月 11 日
    第一行放暂存器,然后取出来,一行可以有多个 sed 命令,命令用 ; 分割
    ficenow
        28
    ficenow  
    OP
       2016 年 1 月 11 日
    @xuboying 我觉得你可能理解错了,我的包含 rows 串的行不在文件的第一行和最后一行的
    kingddc314
        29
    kingddc314  
       2016 年 1 月 11 日
    sed '2,$s/aaa/bbb/g' text
    ficenow
        30
    ficenow  
    OP
       2016 年 1 月 11 日
    @kingddc314 你也理解错了,我的匹配行不在文件的第一行的
    kingddc314
        31
    kingddc314  
       2016 年 1 月 11 日
    @ficenow 看错了,以为你是要从第二行开始替换,结果你是删除
    lululau
        32
    lululau  
       2016 年 1 月 11 日
    sed -i '0,/rows/{//d}'
    kingddc314
        33
    kingddc314  
       2016 年 1 月 11 日
    _rep() {
    text=`sed -n '/$1/p' $2 | head -1`
    n=`sed -n '/$1/=' $2 | head -1`
    sed -i '/$1/d' $2 && sed -i "${n}i $text" $2
    }
    _rep match a.txt
    # 鉴于楼主必须使用 sed ,可以先找出第一次匹配的内容和行号,然后删除后再把这一行给添加在之前的位置
    # ps : osx 的 sed 和 linux 的差别很大!!!
    rrfeng
        34
    rrfeng  
       2016 年 1 月 11 日   ❤️ 2
    看到楼上都没有正确回答,闪开我要装逼了!

    sed '1,/rows/!{/rows/d}'
    rrfeng
        35
    rrfeng  
       2016 年 1 月 11 日
    啊 32 楼已经给出来了……
    kingddc314
        36
    kingddc314  
       2016 年 1 月 11 日 via Android
    @rrfeng 可是楼主要的是保留第一次匹配的行,不是第一行
    xuboying
        37
    xuboying  
       2016 年 1 月 11 日
    @ficenow 不好意思,题目没看清 perl -e '@x=<>;@i = grep { $x[$_]=~/rows/ } 0..$#x;$x[$i[$_]]="" for (1..$#i-1);print @x'
    rrfeng
        38
    rrfeng  
       2016 年 1 月 11 日
    @kingddc314 请自行测试
    kingddc314
        39
    kingddc314  
       2016 年 1 月 11 日
    @rrfeng 我错了,你这确实是对的, good job
    Elethom
        40
    Elethom  
       2016 年 1 月 11 日
    @rrfeng
    僅限 GNU sed 。
    rrfeng
        41
    rrfeng  
       2016 年 1 月 11 日
    @Elethom
    --posix 没有问题。
    ficenow
        42
    ficenow  
    OP
       2016 年 1 月 12 日
    @lululau
    @rrfeng 你们两个的都可以, lululau 的加个!符号就行了,但是如果要保留的是最后一行呢?要怎么办?
    ficenow
        43
    ficenow  
    OP
       2016 年 1 月 12 日
    @xuboying 你这个会保留第一个和最后一个,怎么修改使得之保留第一个或最后一个呢?
    xuboying
        44
    xuboying  
       2016 年 1 月 12 日
    perl -e '@x=<>;@i = grep { $x[$_]=~/rows/ } 0..$#x;$x[$i[$_]]="" for (1..$#i-1);print @x'
    ^----------改成$#i 就把最后一个干掉了
    ^----------改成 0 就把第一个干掉了
    xuboying
        45
    xuboying  
       2016 年 1 月 12 日
    @ficenow
    perl -e '@x=<>;@i = grep { $x[$_]=~/rows/ } 0..$#x;$x[$i[$_]]="" for (1..$#i-1);print @x'
                                       ^----------改成$#i 就把最后一个干掉了
                                     ^----------改成 0 就把第一个干掉了
    yingluck
        46
    yingluck  
       2016 年 1 月 12 日
    awk '!/rows/{print} /rows/{if(a != 1){print;a=1}}'
    tt0411
        47
    tt0411  
       2016 年 1 月 12 日
    @rrfeng 求解释 !{//d} 这部分语法
    lonelinsky
        48
    lonelinsky  
       2016 年 1 月 12 日   ❤️ 1
    @tt0411 要合在一起理解, 1 ,/rows/! 表示 1 ,/rows/之外的行,{/rows/d}表示删除包含 rows 的行…

    @ficenow 偷个巧,保留最后一个可以这样 tac file | sed '1,/rows/!{/rows/d}' | tac
    rrfeng
        49
    rrfeng  
       2016 年 1 月 12 日
    保留最后一行稍微换一下就好了啊
    sed '/rows/,$!{/rows/d}'
    lonelinsky
        50
    lonelinsky  
       2016 年 1 月 13 日
    @rrfeng 这个用来保留最后一个是不对的,你再看看…😂
    ficenow
        51
    ficenow  
    OP
       2016 年 1 月 13 日
    @lonelinsky
    @rrfeng rrfeng 那样不能保留最后一行, lonelinsky 的偷巧方法可以,但是 tac 命令处理文件的时候会把我文件的有些行合并(我也不知道怎么回事),所以把 tac 命令改为 sed '1!G;h;$!d'或 sed -n '1!G;h;$p'是可以的,但是处理速度不理想~~
    lonelinsky
        52
    lonelinsky  
       2016 年 1 月 14 日
    @ficenow 还可以试试这样 sed "`grep -n rows file | tail -1 | cut -d: -f1`! {/rows/d}" file

    至于 tac 会合并的问题我这边没碰到,你试下把会合并的行摘出来看看? 或者用 vim -b 之类看下是不是不换行的地方有问题…
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   4586 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 08:05 · PVG 16:05 · LAX 00:05 · JFK 03:05
    ♥ Do have faith in what you're doing.