• 请不要在回答技术问题时复制粘贴 AI 生成的内容
hujianxin
V2EX  ›  程序员

今天有个小需求,用 awk 和 sed 貌似不能很好的完成任务,打算转战 perl 了

  •  
  •   hujianxin · Dec 5, 2018 · 8341 views
    This topic created in 2892 days ago, the information mentioned may be changed or developed.

    有一个文件,a.txt ,文容如下:

    0689LM  name=S:321, password=154adfv839473, value=37461278216723
    1633LM  name=S:241, password=15sdf78839611, value=21
    1121LM  name=S:673, password=1543978839612, value=1230
    1212LM  name=S:854, password=fd43978df9621, value=383242544
    3323LM  name=S:456, password=sd9788396sdd3, value=11211
    3322LM  name=S:234, password=dsfas78839623, value=23121
    4238LM  name=S:254, password=1fdsafdsafdsa, value=324342
    51LM    name=S:903, password=fdsafsdafsdaf, value=43543
    2389LM  name=S:572, password=fdsfdsdfwefff, value=2343235
    91452LM name=S:842, password=sdfwef23dffds, value=3434324
    9553LM  name=S:fed, password=23fdssfdss32f, value=10501342176
    

    需求:输出第一列的反转,name=S:之后的数字,value 之后的数值,如下:

    ML9860 321 37461278216723
    ML3361 241 21
    ML1211 673 1230
    ML2121 854 383242544
    ML3233 456 11211
    ML2233 234 23121
    ML8324 254 324342
    ML15 903 43543
    ML9832 572 2343235
    ML25419 842 3434324
    ML3559 fed 10501342176
    

    awk,不好实现第一列的反转

    sed,不好显示抓取 name=S:之后的数字(需要非贪婪)

    当然,也可能是我才疏学浅,如果各位大佬有更好的解决方法,欢迎指教。

    perl -aE '/name=S:(.*?),.*?value=(.*)/; $a = reverse $F[0]; say "$a $1 $2"' a.txt

    Supplement 1  ·  Dec 6, 2018
    题目中所提工具有:awk、sed、perl。

    如果有人觉着这些东西落伍了,不够好(比如你觉着写 excel 更好、python 更好),那么你把代码提出来,大家一起讨论一下。简单的来说,就是 show me your code。

    另外,题目中并没有提 shell 这门语言,如果你想喷想疯了的话,自己开一个帖子去喷 shell 如何?
    86 replies  •  2018-12-07 14:44:43 +08:00
    F281M6Dh8DXpD1g2
    F281M6Dh8DXpD1g2
    Dec 5, 2018
    1
    想用 perl 就用 perl 呗
    反正之后你会发现三十秒看不懂的东西都得重写
    hujianxin
    hujianxin
    OP
    Dec 5, 2018
    2
    @liprais oneliner 从来都不是为了复用的啊
    zbinlin
    zbinlin
    Dec 5, 2018
    3
    只用 sed 就可以呀:

    sed -r 's/^([[:digit:]]+)([A-Z]+)\s+name=S:([^,]+),.+value=(.+)$/\2\1 \3 \4/'
    zbinlin
    zbinlin
    Dec 5, 2018
    4
    @zbinlin 呃,没看到第一列的数字反转了
    hujianxin
    hujianxin
    OP
    Dec 5, 2018
    5
    @zbinlin 这个反转,估计用 sed 的保持空间协助一下也能搞定,但是太难了
    yiyiwa
    yiyiwa
    Dec 5, 2018
    6
    这样有点慢啊

    awk -F '[: ,]' '{"rev<<<"$1|getline a;print a,$3,$NF}'
    yiyiwa
    yiyiwa
    Dec 5, 2018
    7
    少个+,
    awk -F '[: ,]+' '{"rev<<<"$1|getline a;print a,$3,$NF}'
    hujianxin
    hujianxin
    OP
    Dec 5, 2018
    8
    @yiyiwa 这条语句在我这里有语法错误呢

    sh: 1: Syntax error: redirection unexpected
    name=S value=37461278216723
    sh: 1: Syntax error: redirection unexpected
    name=S value=21
    sh: 1: Syntax error: redirection unexpected
    name=S value=1230
    sh: 1: Syntax error: redirection unexpected
    name=S value=383242544
    sh: 1: Syntax error: redirection unexpected
    name=S value=11211
    sh: 1: Syntax error: redirection unexpected
    name=S value=23121
    sh: 1: Syntax error: redirection unexpected
    name=S value=324342
    sh: 1: Syntax error: redirection unexpected
    value=43543
    sh: 1: Syntax error: redirection unexpected
    name=S value=2343235
    sh: 1: Syntax error: redirection unexpected
    842 value=3434324
    sh: 1: Syntax error: redirection unexpected
    hujianxin
    hujianxin
    OP
    Dec 5, 2018
    9
    @yiyiwa 还是同样的错误
    yiyiwa
    yiyiwa
    Dec 5, 2018
    10
    awk -F '[: ,=]+' '{s=length($1);for(i=0;i<s;i++)k=k""substr($1,s-i,1);print k,$4,$NF;k=j}'
    rrfeng
    rrfeng
    Dec 5, 2018
    11
    翻转第一列:

    echo .... | while read a b; do echo $(rev <<< $a) $b;done

    如果只有一行的话不需要 while

    echo .... | { read a b; echo $(rev <<< $a) $b; }
    weyou
    weyou
    Dec 5, 2018 via Android
    12
    首先 awk 是可以用循环来反转的,就是麻烦点。第二,rev 命令很多系统都是自带的吧,为什么不用
    rrfeng
    rrfeng
    Dec 5, 2018
    13
    @yiyiwa
    需要关闭管道,在处理行尾加上 close "rev<<<" 试试
    ywgx
    ywgx
    Dec 5, 2018❤️1
    14
    对 vimer 来说,也就是录制个宏,播放一下而已
    hcymk2
    hcymk2
    Dec 5, 2018
    15
    awk 可以自定义函数。
    hujianxin
    hujianxin
    OP
    Dec 5, 2018
    16
    @yiyiwa 这个我也想到啦,但是稍微有点复杂了,长了一些。
    @ywgx 感觉分工还不太一样

    @hcymk2 自定义函数就不是一行了。。
    codechaser
    codechaser
    Dec 5, 2018 via Android
    17
    你们说的我根本看不懂……
    likuku
    likuku
    Dec 5, 2018
    18
    额... 我是突然点进了今天的 黑魔法 9 级课程了么?

    别说 awk sed 了,shell 开始需要用到 判断 语句 我都果断直接用 py3 了。
    zbinlin
    zbinlin
    Dec 5, 2018❤️1
    19
    @zbinlin

    paste -d' ' <(sed -rn 's/^([^ ]+*).+$/\1/p' <filename> | rev) <(sed -rn 's/^.+name=S:([^,]+),.+value=(.+)$/\1 \2/p' <filename>)
    ToT
    ToT
    Dec 5, 2018
    20
    能用 pandas 么。。。。
    xpresslink
    xpresslink
    Dec 5, 2018
    21
    随便用个编程语言打开文件逐行遍历一下就可以。
    YOOHUU
    YOOHUU
    Dec 5, 2018
    22
    shell 这堆玩意....瞎了
    realpg
    realpg
    Dec 6, 2018
    23
    python 不好么
    其实更好的解决方案是 EXCEL
    livepps
    livepps
    Dec 6, 2018 via Android
    24
    python 分分钟的事情
    agagega
    agagega
    Dec 6, 2018
    25
    我想了想用 Ruby,也可以一行搞定,结果可能可读性比你的 Perl 稍微高点点,也没差太多...
    yue9944882
    yue9944882
    Dec 6, 2018❤️2
    26
    写 perl 很多年了。。perl 现在实战的价值就是所谓 one-liner。。谁写的更精简谁就更好,不管可读性。。这也是 perl 同 python 等其他“更高级”的语言的一个优势吧。。有点像所谓降维打击哈哈哈

    (不要学 perl 了,浪费时间)
    congeec
    congeec
    Dec 6, 2018❤️1
    27
    #23 说的对
    我都复制下来,放 excel 里
    写正则还要查一会儿语法
    Tony042
    Tony042
    Dec 6, 2018
    28
    @congeec 放 excel 里怎么实现呢,能大概讲讲吗
    thedrwu
    thedrwu
    Dec 6, 2018 via Android
    29
    perl 作为主力脚本语言十多年,自从因为 numpy 用了 Python,发现回不去 perl 了:
    连 foreach 都不会写了,
    哪些操作会影响$_也忘了。
    嗯?这里的引用要套几层?
    从前的我怎么到处都在用 qw,那是干啥的现在怎么想不起来了…
    重新学 perl 好麻烦,还是退回 bash+sed+awk 算了。
    congeec
    congeec
    Dec 6, 2018
    30
    @Tony042 假设你用 mac, 用 pbcopy/pbpaste 来复制粘贴。windows 也有类似的工具,不过你要自己找
    tips:column 是个很好用的表格格式化命令
    zxcvsh
    zxcvsh
    Dec 6, 2018 via iPhone
    31
    @ToT 你怎么会想到用 pandas 的
    Mithrandir
    Mithrandir
    Dec 6, 2018
    32
    为啥不用 python,或者 awk + sed + python -c
    swordne
    swordne
    Dec 6, 2018
    33
    为啥我觉得这东西在 excel 里就能完成了?
    bellucci1964
    bellucci1964
    Dec 6, 2018
    34
    说 python 就算了,说 excel 的又是什么鬼,ssh 到远程主机上哪来的 excel
    julypanda
    julypanda
    Dec 6, 2018
    35
    不会发图,手动表情
    “这就是强者的世界吗?”
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    36
    不会发图,手动表情
    “ talk is cheap, show me your code or excel picture ”
    thecon
    thecon
    Dec 6, 2018
    37
    正解,oneliner 目前还没有什么能比 perl 更趁手的吧
    bucuoo
    bucuoo
    Dec 6, 2018
    38
    awk 版本
    awk '{gsub(/[[:digit:]]+/,"&=",$1); split($1,aa,"="); split($2,na,"[=:,]"); split($4,va,"="); print aa[2]aa[1]" "na[3]" "va[2]}' a.txt
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    39
    @thedrwu 老哥,都用了 9 年了,这么快就忘了啊
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    40
    @thecon
    简单的任务,awk 更简洁,输入的字符更少,比如我需要看 nginx 日志里面的服务器错误的 log,只需要:awk '$4>=500'。
    但是复杂点的任务,比如我题目中提到的,perl 又更简洁很多,毕竟提供了功能强大的函数。
    如果再复杂的任务,谁还用 oneliner 啊,哈哈
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    41
    @bucuoo 赞
    qinrui
    qinrui
    Dec 6, 2018
    42
    反转是什么鬼?为什么要反转
    operawang
    operawang
    Dec 6, 2018
    44
    文本处理当然是 Perl 当家
    jjianwen68
    jjianwen68
    Dec 6, 2018
    45
    写不来这么复杂的 shell
    xiaket
    xiaket
    Dec 6, 2018
    46
    ```{~}cat a.txt | python3 -c "import sys; \
    > seg1 = lambda line: ''.join(reversed(line.split()[0])); \
    > seg2 = lambda line: line.split()[1].split(':')[1].rstrip(','); \
    > seg3 = lambda line: line.split()[-1].split('=')[-1]; \
    > print(''.join(' '.join([seg1(line), seg2(line), seg3(line), '\n']) for line in sys.stdin.readlines()))"```

    好吧, 这么纠结的需求要放进一行,Python 的效果也一般.
    msg7086
    msg7086
    Dec 6, 2018
    47
    喜欢 Perl 处理文本的可以试试 Ruby ……
    buhi
    buhi
    Dec 6, 2018
    48
    真的是把 shell 这坨狗屎当成宝了...
    ecmascript2020
    ecmascript2020
    Dec 6, 2018
    49
    用 javascript
    xingheng
    xingheng
    Dec 6, 2018
    50
    @buhi 头一次看到有人讽刺 shell 是一坨屎的
    xingheng
    xingheng
    Dec 6, 2018
    51
    用 awk 和 shell 可以实现:

    先分片,找到所有期望的元素:
    awk -F '[[:space:]]+|:|,|=' '{ print $1" "$4" "$10 }'

    然后用 rev 实现反转:
    awk '{ system("echo $(echo "$1" | rev) " ); }'

    拼起来:
    awk -F '[[:space:]]+|:|,|=' '{ system("echo $(echo "$1" | rev) " $4" "$10); }'

    看了一下我的环境,rev 是 BSD 的命令,Linux 和 macOS 都内置
    no1xsyzy
    no1xsyzy
    Dec 6, 2018
    52
    @xingheng 那么你见得少了,shell 作为编程语言确实是一坨屎
    脑子混乱根本不知道自己在干什么的感觉
    shell 就只是个壳罢了。
    如果不需要调用其他程序我一般还是 python 的。
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    53
    @no1xsyzy 这个可能是与智商有关系把,我用 shell 很顺手,脑子也很清晰
    buhi
    buhi
    Dec 6, 2018
    54
    shell 从各方面来说作为一个编程语言都是不合格的, 任何正常的编程语言, 包括被人当成梗鄙视的 php, 都能吊打 shell 七条街, 这个就是屎的定义
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    55
    @xingheng 很赞,学习了
    Vegetable
    Vegetable
    Dec 6, 2018
    56
    工具是在进步的吧,没必要虐待自己不是?
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    57
    @buhi 来来,用你先进的工具完成以下题目的问题如何?
    hujianxin
    hujianxin
    OP
    Dec 6, 2018❤️1
    58
    @buhi 并没有题目中有提 shell 语言吗?提的时 awk、sed、perl。你是不是想喷人想疯了?搞一个假想敌就开始喷
    araraloren
    araraloren
    Dec 6, 2018
    59
    cat **FILE** | perl6 -ne '/ ^ (.*?) \s+ .* \:(\w+) .* "value=" (\d+) $/; say ($0.comb.reverse.join, $1, $2).join("\t")'
    你可以一行行的处理,perl 同理。。
    MarioLuisGarcia
    MarioLuisGarcia
    Dec 6, 2018
    60
    vim macro
    hawhaw
    hawhaw
    Dec 6, 2018
    61
    perl 还是太老了
    但这货实在是强大
    几乎啥场景都能找到包
    直接用
    urmyfaith
    urmyfaith
    Dec 6, 2018
    62
    ![]( )

    你们要到 Excel
    ltux
    ltux
    Dec 6, 2018
    63
    这种问题本来就是 Perl 的强项,awk sed 之类的工具本来压根本就不用学,一门 Perl 走天下即可。 上面说写了后来看不懂的,你写 sed awk 过几天照样看不懂。
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    64
    loopfor
    loopfor
    Dec 6, 2018
    65
    我觉得这种还是 java/c#/c++顺手。
    那些一两行的看似精简,但是可维护性可读性都很差呀,出点问题调试也很麻烦。
    araraloren
    araraloren
    Dec 6, 2018
    66
    @loopfor 但是不是所有东西都需要维护的。。这东西就是用完就扔,下次再写
    yiyizym
    yiyizym
    Dec 6, 2018
    67
    用 awk,自定义一个反转函数:rev

    awk 'function rev(str){if(str == "") return ""; else return (rev(substr(str,2)) substr(str,1,1))} {print rev($1), substr($2,8), substr($4,7)}' a.txt
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    68
    @yiyizym 可惜 awk 没有自带一个这种函数
    yiyizym
    yiyizym
    Dec 6, 2018
    69
    @yiyizym

    第二列多了个逗号,而且把 fed 也算进去了,更正一下:
    awk 'function rev(str){if(str == "") return ""; else return (rev(substr(str,2)) substr(str,1,1))} {print rev($1), gensub(/[^0-9]/,"","g",$2), substr($4,7)}' a.txt
    hellolleh
    hellolleh
    Dec 6, 2018
    70
    why not python?
    lululau
    lululau
    Dec 6, 2018❤️2
    71
    说 Python 的可以试试能不能一分钟之内写出代码来,是的,像这样的不太复杂的文本处理任务用 Perl 一分钟之内就可以写出来代码

    说 Excel 的可以试试算个一千万行或者更大的文本试试?

    Perl 相比 sed / awk 的优势是,你不许区分 perl 还是 gperl,不许记哪些选项和功能是只有 GNU 版本的才有,不需要去区分 basic regex, extended regex, posix regex,你只要会 Perl 正则就可以了

    sed 算是门艺术,偶尔写一下可以陶冶情操,贴一个 sed 实现 rev 的代码,陶冶一下😀

    sed '/\n/!G;s/\(.\)\(.*\n\)/&\2\1/;//D;s/.//'
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    72
    @lululau 这个很陶冶情操,手工再见
    Raymon111111
    Raymon111111
    Dec 6, 2018
    73
    哎呀 java 也可以其实(手动斜眼
    no1xsyzy
    no1xsyzy
    Dec 6, 2018❤️1
    74
    @hujianxin “脑子混乱”并不是指我,而是写出 shell 的人。
    一会想要以简短的字符表明一个意思,比如$+一个字符的那些(这不查那大部头 manual 根本不知道意思);
    一会又不允许简洁地表达,比如单引号的处理(如何在单引号的引用字符串内放一个单引号?先结束前一段单引号字符串,反斜杠转义一个单引号进去,再开启下一段单引号字符,1->4 比反引号地狱还快)。

    这纯是由于 shell 根本不是固定的一个人写的,甚至不是为了同一个目的设计的特性。
    毫无主见地随波逐流地写特性出来。
    只因为“之前有这个特性所以我们还是要保留这个特性”。
    向后兼容只会造成过去的麻烦依旧堆积在那边。
    hujianxin
    hujianxin
    OP
    Dec 6, 2018
    75
    @no1xsyzy oneliner 的话,没有这种问题,因为它根本不需要维护,用完就扔了
    no1xsyzy
    no1xsyzy
    Dec 6, 2018
    76
    @lululau ……能,连 re 都不用
    x=input()之后用 split 爆,一行内分别是
    ''.join(reversed(x.split(" ")[0]))
    x.split("name=S:")[1].split(",")[0]
    x.split(", value=")[-1]
    用 print 输出
    然后因为任意多行的要求,整个框在 while True 里面
    总共写了 40 多秒
    no1xsyzy
    no1xsyzy
    Dec 6, 2018
    77
    @hujianxin 那就不是“ shell 作为编程语言”的情况
    shell 的 oneliner 并不能处理什么东西
    zhuangjia
    zhuangjia
    Dec 6, 2018
    78
    @xingheng 学习了
    shyrock
    shyrock
    Dec 6, 2018
    79
    @lululau emmm。。。这比较方法。。。是 m20p 比冰箱的显示分辨率高的比法?
    Kirscheis
    Kirscheis
    Dec 6, 2018❤️1
    80
    import re

    n = re.compile(r'''name=S:(.{3})''')
    m = re.compile(r'''value=(\d*)''')

    with open('asdf','r') as f:
    s = f.readlines()

    for i in s:
    a,b,c,d = i.split()
    a = a[::-1]
    b = n.match(b).groups()[0]
    d = m.match(d).groups()[0]
    print(a, b ,d)


    python,写了 30 秒左右吧。

    不是说 perl 这些不好,我个人认为新的这些脚本语言的一个优点是,即使没有接触过编程的人,也能大概猜出来它想干什么,因此在过些年过气之后,不至于让大家都觉得遗留的脚本是天书。
    aliipay
    aliipay
    Dec 6, 2018
    81
    @shyrock 差不多吧,所以正确方法应该是选取一个合适的工具。
    lululau
    lululau
    Dec 6, 2018 via iPhone
    82
    学开汽车比学开飞机容易,所以汽车比飞机好,见识短没关系,但是保持开放的心态,先了解再判断
    no1xsyzy
    no1xsyzy
    Dec 6, 2018
    83
    @Kirscheis 不至于让大家都觉得遗留的脚本是天书+1
    这就是我为什么会反对 python 里加 “:=”
    ps1aniuge
    ps1aniuge
    Dec 7, 2018
    84
    #建议保存编码为:bom 头 + utf8

    $输入文件 = 'a:\pscode\TEMP_2018\temp207\aaa.txt'
    $输出文件 = 'a:\pscode\TEMP_2018\temp207\aaa2.txt'

    function 翻转函数($a)
    {
    $b = $a.tochararray()
    [System.Array]::Reverse($b)
    [string]$c = [system.String]::Concat($b)
    return $c
    }

    $所有行 = Get-Content -LiteralPath $输入文件 -ReadCount 0
    $输出的所有行 = @()
    foreach ($行 in $所有行)
    {
    $列 = $行.split(' ',[System.StringSplitOptions]::RemoveEmptyEntries)
    $列 1 = 翻转函数 $列[0]
    $列 2 = $列[1].replace('name=S:','').trimend(',')
    $列 3 = $列[3].replace('value=','')
    $新列 = $列 1,$列 2,$列 3 -join ' '
    $输出的所有行 += $新列
    }
    Set-Content -LiteralPath $输出文件 -Encoding UTF8 -Value $输出的所有行

    powrshell 代码,win,linux 通用。
    源文件不要有尾部空行。
    测试通过。
    ps1aniuge
    ps1aniuge
    Dec 7, 2018
    85
    $列 3 被 V2EX 人为分词了,不怪我
    ps1aniuge
    ps1aniuge
    Dec 7, 2018
    86
    用法:
    在 linux 的 bash 中,用我分享的 powershell 脚本的方法:(需要先安装 linux 版 powershell )
    /usr/bin/pwsh -f "fz 翻转字符串.ps1" -输入字符串 'abcd'



    #建议保存编码为:bom 头 + utf8
    param
    (
    [string]$输入字符串
    )

    $b = $输入字符串.tochararray()
    [System.Array]::Reverse($b)
    $c = [system.String]::Concat($b)
    return $c
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2304 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 213ms · UTC 11:45 · PVG 19:45 · LAX 03:45 · JFK 06:45
    ♥ Do have faith in what you're doing.