Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/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
使用sed内部循环的替代方法_Sed - Fatal编程技术网

使用sed内部循环的替代方法

使用sed内部循环的替代方法,sed,Sed,我希望使用包含一行的文件替换大文件的多行(非连续)行。我发现工作是 for i in ${list[@]}; do line=$(cat file_$i.txt); sed -i "$i c $line" bigfile.txt; done 这里,list包含我要替换的行。以下是一个例子: $ list=(1 3 4 7) $ cat file_1.txt this is the new line 1 $ cat file_3.txt this is the new line 3

我希望使用包含一行的文件替换大文件的多行(非连续)行。我发现工作是

for i in ${list[@]}; do
   line=$(cat file_$i.txt);
   sed -i "$i c $line" bigfile.txt;
done
这里,
list
包含我要替换的行。以下是一个例子:

$ list=(1 3 4 7)
$ cat file_1.txt
this is the new line 1
$ cat file_3.txt
this is the new line 3
$ cat file_4.txt
this is the new line 4
$ cat file_7.txt
this is the new line 7

$ cat bigfile.txt
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
上述脚本的输出是

$ cat bigfile.txt 
newline 1
line 2
newline 3
newline 4
line 5
line 6
newline 7
line 8
它可以工作,但在循环的每一步中,sed都会打开并读取整个文件,据我所知,因此这种方法非常慢。其他更快的方法是什么,最好使用
sed

一种可能的解决方案:

sed "$(for i in $list; do echo "$i c $(cat file_$i.txt)"; done)" bigfile.txt
$list
可能必须是
${list[@]}
${list[*]}
或其他任何内容,具体取决于其构造方式。)


您的原始循环用于构建一个Sed脚本,其中每一行类似于
1c content\u of_file\u 1_dot\u txt
;然后,此脚本仅在
bigfile.txt

上运行一次。忘记
列表[]
数组,并在仅包含您的文件的目录中运行此脚本:

awk '
sub(/^file_/,"",FILENAME) { map[FILENAME+0] = $0; next }
{ print (FNR in map ? map[FNR] : $0) }
' file_*.txt bigfile.txt
或者,如果您也设置使用列表[]数组:

awk -v list="${list[*]}" '
BEGIN {
    split(list,tmp)
    for (i in tmp) {
        lineNrs[tmp[i]]
    }
}
NR in lineNrs {
    if ( (getline line < ("file_" NR ".txt")) > 0 ) {
        $0 = line
    }
    close("file_" NR ".txt")
}
{ print }
' bigfile.txt
awk-v list=“${list[*]}”
开始{
拆分(列表,tmp)
对于(tmp中的i){
线路编号[tmp[i]]
}
}
衬板中的NR{
如果((getline<(“file_“NR.txt”))>0){
$0=行
}
关闭(“文件”NR.txt)
}
{print}
'bigfile.txt
这可能适合您(GNU-sed和并行):

或者,如果替换文本文件每行仅包含一行:

parallel echo '{}c$(<file_{}.txt)' ::: ${list[@]} | sed -i -f - bigfile

请注意,不要使用反勾号替换命令;改为使用
$(
,这样可读性更强,而且可以很容易地嵌套。要想弄清楚你想做什么有点困难,你能澄清一下吗?让shellcheck.net也对您的脚本进行更正。我有一个来自模拟的大数据文件,其中每个模拟对应一行,但其中一些很早就停止了,所以我再次运行了它们。现在,我想用相应行中的新数据替换它们的行,而不需要手动执行此操作。我会编辑这篇文章,但我认为否决票是不必要的。@RenanNobuyukiHirayama,如果这个问题没有显示任何研究成果,否决票是必要的;这是不清楚或没有用处。此外,您的脚本在
bigfile.txt
的最后一行之前插入所有
,那么您所说的“正确位置”在哪里?它起作用了,谢谢!我只需将
$list
更改为
${list[@]}
(我对bash数组仍然不太熟悉)。哇,这就是嵌套+1.请读者记住,这保证可以与GNU sed一起使用,但不能与POSIX sed一起使用。
parallel 'echo "{}r file_{}.txt";echo "{}d"' ::: ${list[@]} | sed -i -f - bigfile
parallel echo '{}c$(<file_{}.txt)' ::: ${list[@]} | sed -i -f - bigfile
parallel --rpl '{@} s/[^0-9]//g' 'echo "{@}r {}";echo "{@}d"' ::: file_* |
sed -i -f - bigfile