How to use sed to replace only the first occurrence in a file?

前端 未结 23 840
别跟我提以往
别跟我提以往 2020-11-22 04:27

I would like to update a large number of C++ source files with an extra include directive before any existing #includes. For this sort of task, I normally use a small bash s

相关标签:
23条回答
  • 2020-11-22 04:38

    Quite a comprehensive collection of answers on linuxtopia sed FAQ. It also highlights that some answers people provided won't work with non-GNU version of sed, eg

    sed '0,/RE/s//to_that/' file
    

    in non-GNU version will have to be

    sed -e '1s/RE/to_that/;t' -e '1,/RE/s//to_that/'
    

    However, this version won't work with gnu sed.

    Here's a version that works with both:

    -e '/RE/{s//to_that/;:a' -e '$!N;$!ba' -e '}'
    

    ex:

    sed -e '/Apple/{s//Banana/;:a' -e '$!N;$!ba' -e '}' filename
    
    0 讨论(0)
  • 2020-11-22 04:39

    As an alternative suggestion you may want to look at the ed command.

    man 1 ed
    
    teststr='
    #include <stdio.h>
    #include <stdlib.h>
    #include <inttypes.h>
    '
    
    # for in-place file editing use "ed -s file" and replace ",p" with "w"
    # cf. http://wiki.bash-hackers.org/howto/edit-ed
    cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s <(echo "$teststr")
       H
       /# *include/i
       #include "newfile.h"
       .
       ,p
       q
    EOF
    
    0 讨论(0)
  • 2020-11-22 04:42

    A possible solution here might be to tell the compiler to include the header without it being mentioned in the source files. IN GCC there are these options:

       -include file
           Process file as if "#include "file"" appeared as the first line of
           the primary source file.  However, the first directory searched for
           file is the preprocessor's working directory instead of the
           directory containing the main source file.  If not found there, it
           is searched for in the remainder of the "#include "..."" search
           chain as normal.
    
           If multiple -include options are given, the files are included in
           the order they appear on the command line.
    
       -imacros file
           Exactly like -include, except that any output produced by scanning
           file is thrown away.  Macros it defines remain defined.  This
           allows you to acquire all the macros from a header without also
           processing its declarations.
    
           All files specified by -imacros are processed before all files
           specified by -include.
    

    Microsoft's compiler has the /FI (forced include) option.

    This feature can be handy for some common header, like platform configuration. The Linux kernel's Makefile uses -include for this.

    0 讨论(0)
  • 2020-11-22 04:43

    If anyone came here to replace a character for the first occurrence in all lines (like myself), use this:

    sed '/old/s/old/new/1' file
    
    -bash-4.2$ cat file
    123a456a789a
    12a34a56
    a12
    -bash-4.2$ sed '/a/s/a/b/1' file
    123b456a789a
    12b34a56
    b12
    

    By changing 1 to 2 for example, you can replace all the second a's only instead.

    0 讨论(0)
  • 2020-11-22 04:44

    With GNU sed's -z option you could process the whole file as if it was only one line. That way a s/…/…/ would only replace the first match in the whole file. Remember: s/…/…/ only replaces the first match in each line, but with the -z option sed treats the whole file as a single line.

    sed -z 's/#include/#include "newfile.h"\n#include'
    

    In the general case you have to rewrite your sed expression since the pattern space now holds the whole file instead of just one line. Some examples:

    • s/text.*// can be rewritten as s/text[^\n]*//. [^\n] matches everything except the newline character. [^\n]* will match all symbols after text until a newline is reached.
    • s/^text// can be rewritten as s/(^|\n)text//.
    • s/text$// can be rewritten as s/text(\n|$)//.
    0 讨论(0)
  • 2020-11-22 04:45
     # sed script to change "foo" to "bar" only on the first occurrence
     1{x;s/^/first/;x;}
     1,/foo/{x;/first/s///;x;s/foo/bar/;}
     #---end of script---
    

    or, if you prefer: Editor's note: works with GNU sed only.

    sed '0,/foo/s//bar/' file 
    

    Source

    0 讨论(0)
提交回复
热议问题