Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 为多个sed替换优化shell脚本_Bash_Shell_Sed - Fatal编程技术网

Bash 为多个sed替换优化shell脚本

Bash 为多个sed替换优化shell脚本,bash,shell,sed,Bash,Shell,Sed,我有一个文件,其中包含替换对的列表(大约100个),sed使用这些替换对替换文件中的字符串 这对像: old|new tobereplaced|replacement (stuffiwant).*(too)|\1\2 我现在的代码是: cat replacement_list | while read i do old=$(echo "$i" | awk -F'|' '{print $1}') #due to the need for extended regex new

我有一个文件,其中包含替换对的列表(大约100个),sed使用这些替换对替换文件中的字符串

这对像:

old|new
tobereplaced|replacement
(stuffiwant).*(too)|\1\2
我现在的代码是:

cat replacement_list | while read i
do
    old=$(echo "$i" | awk -F'|' '{print $1}')    #due to the need for extended regex
    new=$(echo "$i" | awk -F'|' '{print $2}')
    sed -r "s/`echo "$old"`/`echo "$new"`/g" -i file
done
我忍不住认为有一种更为理想的替换方式。我试着把循环转过来,先遍历文件的行,但结果是成本要高得多

有没有其他加速脚本的方法

编辑

感谢所有的快速回复。在选择答案之前,让我先尝试一下各种建议

有一件事需要澄清:我还需要子表达式/组功能。例如,我可能需要的一个替代品是:

([0-9])U|\10  #the extra brackets and escapes were required for my original code
有关改进的一些详细信息(待更新):

  • 方法:处理时间
  • 原始脚本:0.85s
  • cut
    代替
    awk
    :0.71s
  • 阿努巴瓦法:0.18s
  • chthonicdaemon法:0.01s

我最近对各种字符串替换方法进行了基准测试,其中包括一个定制程序,
sed-e
,以及一个可能不那么广为人知的MySQL命令行实用程序,
replace
。为字符串替换进行优化几乎比sed快一个数量级。结果如下所示(最慢优先):

如果您想要性能,请使用。不过,要在您的系统上使用它,您需要安装一些MySQL发行版

发件人:

替换文本文件中的字符串

此程序将替换文件中的字符串或从stdin到stdout的字符串。它接受从字符串/到字符串对的列表,并用对应的to字符串替换from字符串的每次出现。找到的字符串的第一个匹配项。如果替换字符串的可能性不止一种,则在替换较短的匹配之前,首选较长的匹配

程序对字符串进行DFA状态机,速度不取决于替换字符串的数量(仅取决于替换的数量)。假定一行以\n或\0结尾。字符串的长度没有超出内存的限制


更多关于sed。通过将替换件拆分为#CPU组,然后通过
sed
命令对其进行管道传输,您可以在sed中使用多个内核,如下所示:

$ sed -e 's/A/B/g; ...' file.txt | \
  sed -e 's/B/C/g; ...' | \
  sed -e 's/C/D/g; ...' | \
  sed -e 's/D/E/g; ...' > out
# first, split my replace-list into manageable chunks (89 files in this case)
split -a 4 -l 1000 80kReplacePairs rep_

# next, make a 'replace' script out of each chunk
for F in rep_* ; do \
    echo "create and make executable a scriptfile" ; \
    echo '#!/bin/sh' > run_$F.sh ; chmod +x run_$F.sh ; \
    echo "for each chunk-file line, strip line-ends," ; \
    echo "then with sed, turn '{long list}' into 'cat in | {long list}' > out" ; \
    cat $F | tr '\n' ' ' | sed 's/^/cat in | replace /;s/$/ > out/' >> run_$F.sh ;
    echo "and append commands to switch in and out files, for next script" ; \
    echo -e " && \\\\ \nrm in && mv out in\n" >> run_$F.sh ; \
done

# put all the replace-scripts in sequence into a main script
ls ./run_rep_aa* > allrun.sh

# make it executable
chmod +x allrun.sh 

# run it
nohup ./allrun.sh &
此外,如果您使用
sed
perl
,并且您的系统具有UTF-8设置,那么在命令前面放置
LANG=C
也会提高性能:

$ LANG=C sed ...

您可以减少不必要的awk调用,并使用BASH断开名称-值对:

while IFS='|' read -r old new; do
   # echo "$old :: $new"
   sed -i "s~$old~$new~g" file
done < replacement_list
而IFS='|'read-r old new;做
#echo“$old::$new”
sed-i“s~$old~$new~g”文件
完成<更换列表
IFS=“|”将在两个不同的shell变量
old
new
中提供enable read来填充名称值


这是假设您的名称-值对中不存在
~
。如果情况并非如此,则可以随意使用备用的sed分隔符。

您可以使用
sed
生成格式正确的
sed
输入:

sed -e 's/^/s|/; s/$/|g/' replacement_list | sed -r -f - file
你可以试试这个

pattern=''
cat replacement_list | while read i
do
    old=$(echo "$i" | awk -F'|' '{print $1}')    #due to the need for extended regex
    new=$(echo "$i" | awk -F'|' '{print $2}')
    pattern=${pattern}"s/${old}/${new}/g;"
done
sed -r ${pattern} -i file
这将在包含所有替换项的文件上仅运行一次sed命令。您可能还想将
awk
替换为
cut
cut
可能比
awk
更优化,尽管我不确定这一点

old=`echo $i | cut -d"|" -f1`
new=`echo $i | cut -d"|" -f2`

您可能希望在awk中完成整个过程:

awk -F\| 'NR==FNR{old[++n]=$1;new[n]=$2;next}{for(i=1;i<=n;++i)gsub(old[i],new[i])}1' replacement_list file

awk-F\|'NR==FNR{old[++n]=$1;new[n]=$2;next}{for(i=1;i以下是我将尝试的:

  • 将您的
    sed
    search-replace对存储在Bash数组中,如下所示:
  • 使用以下命令基于此阵列生成sed命令
  • 运行命令
  • 模式=(
    新旧
    置换
    )
    模式计数=${#模式[*]}#模式数
    sedArgs=()#将保存sed参数列表
    对于((i=0;i
    通过sed编写代码更有趣。请尝试一次性能测试,因为这只启动1个sed,这是递归的

    对于posix sed(带GNU sed的so
    --posix

    解释

    • 使用分隔符复制文件内容前面的替换列表(用于带
      的行和带
      -End-
      的列表),以便于sed处理(posix sed中很难使用\n类内字符)
    • 将所有行放入缓冲区(为替换列表和-End-before添加行分隔符)
    • 如果这是
      -End-³
      ,请删除该行并转到最终打印
    • 用第二个模式(第2组)替换文本中的第一个模式(第1组)
    • 如果找到,重新启动(
      t再次
    • 删除第一行
    • 重新启动进程(
      t再次
      )。需要t,因为
      b
      不会重置测试,并且下一个
      t
      始终为真
      • 多亏了上面的@miku

        我有一个100MB的文件,其中包含80k替换字符串的列表

        我尝试了sed的顺序或并行的各种组合,但没有发现吞吐量比大约20小时的运行时间短

        相反,我将我的列表放入了一系列脚本中,比如“cat-in | replace-aoldanew-bold bnew-cold-cnew…>out;rm-in;mv-out-in”

        我在每个文件中随机挑选了1000个替换项,所以都是这样的:

        $ sed -e 's/A/B/g; ...' file.txt | \
          sed -e 's/B/C/g; ...' | \
          sed -e 's/C/D/g; ...' | \
          sed -e 's/D/E/g; ...' > out
        
        # first, split my replace-list into manageable chunks (89 files in this case)
        split -a 4 -l 1000 80kReplacePairs rep_
        
        # next, make a 'replace' script out of each chunk
        for F in rep_* ; do \
            echo "create and make executable a scriptfile" ; \
            echo '#!/bin/sh' > run_$F.sh ; chmod +x run_$F.sh ; \
            echo "for each chunk-file line, strip line-ends," ; \
            echo "then with sed, turn '{long list}' into 'cat in | {long list}' > out" ; \
            cat $F | tr '\n' ' ' | sed 's/^/cat in | replace /;s/$/ > out/' >> run_$F.sh ;
            echo "and append commands to switch in and out files, for next script" ; \
            echo -e " && \\\\ \nrm in && mv out in\n" >> run_$F.sh ; \
        done
        
        # put all the replace-scripts in sequence into a main script
        ls ./run_rep_aa* > allrun.sh
        
        # make it executable
        chmod +x allrun.sh 
        
        # run it
        nohup ./allrun.sh &
        
        …运行时间不到5分钟,远远少于20小时

        回过头来看,我本可以在每个脚本中使用更多的对,通过找出多少行可以弥补这个限制

        xargs --show-limits </dev/null 2>&1 | grep --color=always "actually use:"
            Maximum length of command we could actually use: 2090490
        

        因此,我似乎可以在这个主题上使用2*40000行块,使用N个
        -e
        或N个单数sed命令时sed运行得更快吗?当N>100.IIRC时,在单个
        sed
        命令中使用替换的
        N
        N
        number
        sed
        命令快一点。我记得being有点惊讶,并行运行几百个进程并没有降低性能
        head -c 2090490 80kReplacePairs | wc -l
        
            76923