代码之家  ›  专栏  ›  技术社区  ›  sixtyfootersdude

将sed's/c/d/'myfile的输出重定向到myfile

  •  18
  • sixtyfootersdude  · 技术社区  · 14 年前

    我在脚本中使用sed进行替换,希望替换的文件覆盖该文件。通常我认为你会用这个:

    % sed -i 's/cat/dog/' manipulate
    sed: illegal option -- i
    

    但是正如你所看到的,我的sed没有这个命令。

    我试过这个:

    % sed 's/cat/dog/' manipulate > manipulate
    

    但这只是将操纵变成一个空文件(有意义)。

    这工作:

    % sed 's/cat/dog/' manipulate > tmp; mv tmp manipulate
    

    但我想知道是否有一种标准方法可以将输出重定向到从中获取输入的同一个文件中。

    10 回复  |  直到 8 年前
        1
  •  37
  •   Nathan Kidd    8 年前

    我通常使用第三种方式,但是 重大变化 :

    $ sed 's/cat/dog/' manipulate > tmp && mv tmp manipulate

    即改变 ; && 因此,只有sed成功时才会移动;否则一旦在sed语法中输入错误,就会丢失原始文件。

    注意! 对于那些读了标题却忽略了操作限制的人 “我的sed不支持 -i :对于大多数人,sed将支持 -我 ,所以最好的方法是:

    $ sed -i 's/cat/dog/' manipulate

        2
  •  8
  •   gatt    13 年前

    对, -i 在freebsd/macosx中也支持 sed ,但需要将空字符串作为参数来就地编辑文件。

    sed -i "" 's/old/new/g' file   # FreeBSD sed
    
        3
  •  6
  •   amertune    14 年前

    如果不想移动副本,可以使用ed:

    ed file.txt <<EOF
    %s/cat/dog/
    wq
    EOF
    
        4
  •  3
  •   Alok Singhal    14 年前

    克尼根和派克 unix编程的艺术 讨论这个问题。他们的解决方案是编写一个名为 overwrite ,它允许一个人做这样的事情。

    用法是: 重写 file cmd 文件 .

    # overwrite: copy standard input to output after EOF
    
    opath=$PATH
    PATH=/bin:/usr/bin
    
    case $# in
    0|1)   echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2
    esac
    
    file=$1; shift
    new=/tmp/overwr1.$$; old=/tmp/overwr2.$$
    trap 'rm -f $new $old; exit 1' 1 2 15  # clean up
    
    if PATH=$opath "$@" >$new
    then
           cp $file $old           # save original
           trap '' 1 2 15          # wr are commmitted
           cp $new $file
    else
           echo "overwrite: $1 failed, $file unchanged" 1>&2
           exit 1
    fi
    rm -f $new $old
    

    一旦你有了上面的脚本 $PATH ,您可以:

    overwrite manipulate sed 's/cat/dog/' manipulate
    

    为了让你的生活更轻松,你可以使用 replace 同一本书的剧本:

    # replace: replace  str1 in files with str2 in place
    PATH=/bin:/usr/bin
    
    case $# in
        0|2) echo 'Usage: replace str1 str2 files' 1>&2; exit 1
    esac
    
    left="$1"; right="$2"; shift; shift
    
    for i
    do
        overwrite $i sed "s@$left@$right@g" $i
    done
    

    代替 在你 $路径 也会让你说:

    replace cat dog manipulate
    
        5
  •  2
  •   nh2    13 年前

    你可以使用 sponge moreutils .

    sed "s/cat/dog/" manipulate | sponge manipulate
    
        6
  •  1
  •   falstro    14 年前

    也许 -i 是gnu-sed,还是sed的旧版本,但无论如何。你在正确的轨道上。第一个选项可能是最常见的一个,第三个选项是如果您希望它在任何地方(包括solaris机器)都能工作……:)这些都是“标准”的做法。

        7
  •  1
  •   Stenemo    11 年前

    要更改多个文件(并将每个文件的备份另存为*.bak),请执行以下操作:

    perl-p-i-e“s/oldtext/newtext/g”*

    replaces any occurence of oldtext by newtext in all files in the current folder. However you will have to escape all perl special characters within oldtext and newtext using the backslash 
    
    This is called a “Perl pie” (mnemonic: easy as a pie)
    The -i flag tells it do do in-place replacement, and it should be ok to use single (“'”) as well as double (“””) quotes.
    
        If using ./* instead of just *, you should be able to do it in all sub-directories 
    See man perlrun for more details, including how to take a backup file of the original.
    using sed:
                sed -i    's/old/new/g' ./*  (used in GNU)
        sed -i '' 's/old/new/g' ./*  (used in FreeBSD)
    
        8
  •  0
  •   mouviciel    14 年前

    -i 选项在标准中不可用 sed .

    你的选择是你的第三条路或者 perl .

        9
  •  0
  •   Vladimir Prudnikov    10 年前

    很多答案,但没有一个是正确的。以下是正确且最简单的:

    $ echo "111 222 333" > file.txt
    $ sed -i -s s/222/444/ file.txt 
    $ cat file.txt
    111 444 333
    $ 
    
        10
  •  -2
  •   Jürgen Hötzel    14 年前

    使用打开文件句柄的解决方法:

    exec 3<manipulate 
    

    防止截断打开的文件:

    rm manipulate
    sed 's/cat/dog/' <&3 > manipulate