AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 1114510
Accepted
Ibraheem
Ibraheem
Asked: 2019-02-01 10:22:30 +0800 CST2019-02-01 10:22:30 +0800 CST 2019-02-01 10:22:30 +0800 CST

在 Ubuntu 上进行一些处理后,BASH 脚本挂起

  • 772

我一直在 Red Hat 服务器上运行下面的脚本,它工作正常并完成了工作。我正在提供的文件包含半百万行(大约 500000 行),这就是为什么(为了更快地完成它)我在 while 循环块的末尾添加了一个“&”

但是现在我已经设置了一个运行 Ubuntu 18.04 的 8 GB RAM 的桌面,并且运行相同的代码只完成了几千行然后挂起。我读了一些关于它的内容并将堆栈限制也增加到了无限制,但它仍然在 80000 行左右后挂起,关于如何优化代码或调整我的 PC 参数以始终完成工作的任何建议?

while read -r CID60
do    
 { 
       OLT=$(echo "$CID60" | cut -d"|" -f5) 
       ONID=${OLT}:$(echo "$CID60" | cut -d, -f2 | sed 's/ //g ; s/).*|//') 
       echo $ONID,$(echo "$CID60" | cut -d"|" -f3) >> $localpath/CID_$logfile.csv       
  } &     
done < $localpath/$CID7360

输入:

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ASSN45| Unlocked|12-654-0330|Up|202-00_MSRFKH00OL6|P282018767.C2028 ( network, R1.S1.LT7.PON8.ONT81.SERV1 )|

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ASSN46| Unlocked|12-654-0330|Down|202-00_MSRFKH00OL6|P282017856.C881 ( local, R1.S1.LT7.PON8.ONT81.C1.P1 )|

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ASSN52| Unlocked|12-664-1186|Up|202-00_MSRFKH00OL6|P282012623.C2028 ( network, R1.S1.LT7.PON8.ONT75.SERV1 )|

输出:

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330

202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186

我感兴趣的输出是第 5 列(用管道分隔|)与最后一列的一部分连接,然后是第三列

bash text-processing background-process
  • 5 5 个回答
  • 1343 Views

5 个回答

  • Voted
  1. xenoid
    2019-02-02T02:53:44+08:002019-02-02T02:53:44+08:00

    纯 sed 解决方案:

    sed -r 's/^[^|]+\|[^|]+\|([^|]+)\|[^|]+\|([^|]+)\|.+\( .+, ([^ ]+).+/\2:\3,\1/' <in.dat >out.dat
    
    • 5
  2. Ole Tange
    2019-02-03T23:54:52+08:002019-02-03T23:54:52+08:00
    doit() {
      # Hattip to @sudodus
      tr ' ' '|' |
        tr -s '|' '|' |
        cut -d '|' -f 3,5,9 
    }
    export -f doit
    parallel -k --pipepart --block -1 -a input.txt doit > output.txt
    
    • -k保持顺序,所以输入的第一/最后一行也将是输出的第一/最后一行
    • --pipepart即时拆分文件
    • --block -1每个 CPU 线程分成 1 个块
    • -a input.txt要拆分的文件
    • doit要调用的命令(或 bash 函数)

    Speedwise parallel(黄色)版本tr在我的系统上优于(黑色)大约 200 MB(秒 vs MB):

    图形

    • 5
  3. sudodus
    2019-02-02T02:47:17+08:002019-02-02T02:47:17+08:00

    我和其他人的oneliners以及一些测试过的脚本

    如果项目和分隔符的顺序可能与您在问题中指定的不同,我认为下面的单行会做到这一点,

    < input tr ' ' '|' | cut -d '|' -f 4,6,10 > output
    

    但是在您写的评论中,您需要完全指定的格式。

    我添加了一个带有'awk'的解决方案,这与 PerlDuck 的带有perl. 请参阅此答案的结尾。

    < input awk '{gsub("\\|"," "); print $5 ":" $9 "," $3}' > output
    

    oneliners和小脚本的测试

    测试是在我的计算机上使用 Lubuntu 18.04.1 LTS、2*2 处理器和 4 GiB RAM 完成的。

    我infile从您的演示(1572864 行)中“加倍 20 倍”,因此获得了巨大的input收益,因此您的 500000 行有一些余量,

    Onelinercut和sed:

    $ < infile cut -d '|' -f 3,5,6 | sed -e 's/|[A-Z].*, /|/' -e 's/ )$//' > outfile
    $ wc -l infile
    1572864 infile
    $ wc -l outfile
    1572864 outfile
    $ tail outfile
    12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
    12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
    12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
    12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
    

    定时

    我们可能会期望,纯sed解决方案会更快,但我认为数据的重新排序会减慢速度,因此cut解决sed方案会更快。这两种解决方案都可以在我的计算机上正常工作。

    Onelinercut和sed:

    $ time < infile cut -d '|' -f 3,5,6 | sed -e 's/|[A-Z].*, /|/' -e 's/ )$//' > outfile
    
    real    0m8,132s
    user    0m8,633s
    sys     0m0,617s
    

    xenoid的纯sedoneliner:

    $ time sed -r 's/^[^|]+\|[^|]+\|([^|]+)\|[^|]+\|([^|]+)\|.+\( .+, ([^ ]+).+/\2:\3,\1/' <infile > outfile-sed 
    
    real    1m8,686s
    user    1m8,259s
    sys     0m0,344s
    

    pythonxeniod 使用具有非贪婪匹配的正则表达式的脚本:

    #!/usr/bin/python
    
    import sys,re
    
    pattern=re.compile(r'^[^|]+?\|[^|]+?\|([^|]+?)\|[^|]+?\|([^|]+?)\|[^,]+?, (.+) \)\|$')
    
    for line in sys.stdin:
        match=pattern.match(line)
            if match:
                print(match.group(2)+':'+match.group(3)+','+match.group(1))
    
    $ time < infile ./python-ng > outfile.pyng
    
    real    0m8,055s
    user    0m7,359s
    sys 0m0,300s
    
    $ python --version
    Python 2.7.15rc1
    

    PerlDuck的perloneliner 比以前的 oneliner 更快:

    $ time perl -lne 'print "$2:$3,$1" if /^(?:[^|]+\|){2}([^|]+)\|[^|]+\|([^|]+)\|[^,]+,\s*(\S+)/;' < infile > outfile.perl
    
    real    0m5,929s
    user    0m5,339s
    sys     0m0,256s
    

    tr带有和cut带有命令的Oneliner tr -s:

    我曾经tr将输入文件中的空格转换为管道字符,然后cut可以在没有sed. 如您所见,tr比 快得多sed。该tr -s命令删除输入中的双管道,这是一个好主意,特别是如果输入文件中可能存在重复的空格或管道。它的成本并不高。

    $ time < infile tr ' ' '|' | tr -s '|' '|' | cut -d '|' -f 3,5,9 > outfile-tr-cut
    
    real    0m1,277s
    user    0m1,781s
    sys     0m0,925s
    

    tr带和cut不带命令的Oneliner,tr -s迄今为止最快:

    time < infile tr ' ' '|' | cut -d '|' -f 4,6,10 > outfile-tr-cut
    
    real    0m1,199s
    user    0m1,020s
    sys     0m0,618s
    
    
    $ tail outfile-tr-cut
    12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
    12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
    12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.SERV1
    12-654-0330|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT81.C1.P1
    12-664-1186|202-00_MSRFKH00OL6|R1.S1.LT7.PON8.ONT75.SERV1
    

    Oneliner 具有awk, 快但不是最快的,

    < input awk '{gsub("\\|"," "); print $5 ":" $9 "," $3}' > output
    
    $ time < infile awk '{gsub("\\|"," "); print $5 ":" $9 "," $3}' > outfile.awk
    
    real    0m5,091s
    user    0m4,724s
    sys     0m0,365s
    

    awk根据parallelOle Tange 实施,将实时时间从 5s 减少到 2s:

    #!/bin/bash
    
    doit() {
     awk '{gsub("\\|"," "); print $5 ":" $9 "," $3}'
    }
    export -f doit
    parallel -k --pipepart --block -1 -a infile doit > outfile.parallel-awk
    
    $ time ./parallel-awk 
    # Academic tradition requires you to cite works you base your article on.
    # When using programs that use GNU Parallel to process data for publication
    #please cite:
    
    #  O. Tange (2011): GNU Parallel - The Command-Line Power Tool,
    #  ;login: The USENIX Magazine, February 2011:42-47.
    
    # This helps funding further development; AND IT WON'T COST YOU A CENT.
    #If you pay 10000 EUR you should feel free to use GNU Parallel without citing.
    
    # To silence this citation notice: run 'parallel --citation'.
    
    real    0m1,994s
    user    0m5,015s
    sys     0m0,984s
    

    parallel正如 Ola Tange 对此问题的回答中的图表所描述的那样,我们可以预期随着输入文件的大小增大,优势会增加。

    速度总结:根据 time四舍五入到小数点后的“真实”时间

    1m 8.7s - sed
       8.1s - cut & sed
       7.4s - python
       5.9s - perl
       5.1s - awk
       2.0s - parallel & awk
       1.2s - tr & cut
    

    最后,我注意到带有sed, python, perl,awk和 { parallel& awk} 的单行代码创建了一个具有规定格式的输出文件。

    $ tail outfile.awk
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186
    
    • 3
  4. Best Answer
    PerlDuck
    2019-02-02T04:58:51+08:002019-02-02T04:58:51+08:00

    Perl 解决方案

    该脚本不会并行执行任何操作,但无论如何都非常快。将其另存为filter.pl(或您喜欢的任何名称)并使其可执行。

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    while( <> ) {
        if ( /^(?:[^|]+\|){2}([^|]+)\|[^|]+\|([^|]+)\|[^,]+,\s*(\S+)/ ) {
            print "$2:$3,$1\n";
        }
    }
    

    我复制了您的示例数据,直到获得 1,572,864 行,然后按如下方式运行:

    me@ubuntu:~> time ./filter.pl < input.txt > output.txt
    real    0m3,603s
    user    0m3,487s
    sys     0m0,100s
    
    me@ubuntu:~> tail -3 output.txt
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.SERV1,12-654-0330
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT81.C1.P1,12-654-0330
    202-00_MSRFKH00OL6:R1.S1.LT7.PON8.ONT75.SERV1,12-664-1186
    

    如果您更喜欢单线,请执行以下操作:

    perl -lne 'print "$2:$3,$1" if /^(?:[^|]+\|){2}([^|]+)\|[^|]+\|([^|]+)\|[^,]+,\s*(\S+)/;' < input.txt > output.txt
    
    • 3
  5. xenoid
    2019-02-02T13:04:46+08:002019-02-02T13:04:46+08:00

    Python

    import sys,re
    
    pattern=re.compile(r'^.+\|.+\|(.+)\|.+\|(.+)\|.+, (.+) \)\|$')
    
    for line in sys.stdin:
    match=pattern.match(line)
    if match:
        print(match.group(2)+':'+match.group(3)+','+match.group(1))
    

    (适用于 Python2 和 Python3)

    使用具有非贪婪匹配的正则表达式快 4 倍(避免回溯?),并使 python 与 cut/sed 方法相提并论(python2 比 python3 快一点)

    import sys,re
    
    pattern=re.compile(r'^[^|]+?\|[^|]+?\|([^|]+?)\|[^|]+?\|([^|]+?)\|[^,]+?, (.+) \)\|$')
    
    for line in sys.stdin:
    match=pattern.match(line)
    if match:
        print(match.group(2)+':'+match.group(3)+','+match.group(1))
    
    • 2

相关问题

  • 同时复制到两个位置

  • 如何在 shell 脚本中创建选择菜单?

  • 从 bash 迁移到 zsh [关闭]

  • bashrc 还是 bash_profile?

  • 备份 bash 脚本未压缩其 tarball

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve