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

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

  •  
  •   ficenow · 2016-01-11 19:42:49 +08:00 · 4018 次点击
    这是一个创建于 3223 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    至于 tac 会合并的问题我这边没碰到,你试下把会合并的行摘出来看看? 或者用 vim -b 之类看下是不是不换行的地方有问题…
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3254 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 10:42 · PVG 18:42 · LAX 02:42 · JFK 05:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.