Asked  7 Months ago    Answers:  5   Viewed   239 times

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 script with sed to re-write the file.

How do I get sed to replace just the first occurrence of a string in a file rather than replacing every occurrence?

If I use

sed s/#include/#include "newfile.h"n#include/

it replaces all #includes.

Alternative suggestions to achieve the same thing are also welcome.

 Answers

92
 # 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

Tuesday, June 1, 2021
 
superfell
answered 7 Months ago
50
sed -n '16224,16482p;16483q' filename > newfile

From the sed manual:

p - Print out the pattern space (to the standard output). This command is usually only used in conjunction with the -n command-line option.

n - If auto-print is not disabled, print the pattern space, then, regardless, replace the pattern space with the next line of input. If there is no more input then sed exits without processing any more commands.

q - Exit sed without processing any more commands or input. Note that the current pattern space is printed if auto-print is not disabled with the -n option.

and

Addresses in a sed script can be in any of the following forms:

number Specifying a line number will match only that line in the input.

An address range can be specified by specifying two addresses separated by a comma (,). An address range matches lines starting from where the first address matches, and continues until the second address matches (inclusively).

Tuesday, June 1, 2021
 
Freddie
answered 7 Months ago
22

In your command s//fonts/../fonts/ is being taken as the parameter to the -i option (the suffix to use for the backup file), and the filename argument is being treated as the editing commands.

You need to specify to disable the backup file creation:

sed -i '' ...

In your example:

sed -i '' 's//fonts/../fonts/' /Users/sergeybasharov/WebstormProjects/snap/compiled/Content/stylesheets/style.css

Computers are dumb, they don't figure things out by context, so they can't tell that something beginning with s/ is obviously an editing command, not a suffix.

Monday, August 2, 2021
 
Jared
answered 5 Months ago
99

you can use fileinput

>>> import fileinput
>>> for linenum,line in enumerate( fileinput.FileInput("file",inplace=1) ):
...   if linenum==0 :
...     print "new line"
...     print line.rstrip()
...   else:
...     print line.rstrip()
...
Saturday, October 23, 2021
 
Hexaholic
answered 2 Months ago
36

Try the following:

echo "0+223+141+800+450+1*(106+400)+1*(1822+500)+1*(183+400)" |
    sed 's/(*([^+]*)+/1suma/g'

which yields:

0+223+141+800+450+1*(106suma400)+1*(1822suma500)+1*(183suma400)

The trick is to avoid sed's invariably greedy matching, so expression [^+]* is used instead of .*, so as to only match up to the next +.


Note that your attempt didn't only replace the last occurrence of your intended pattern, but - due to greedy matching - found only 1 match spanning multiple intended patterns, which it replaced:

*(.*)+ matched *(106+400)+1*(1822+500)+1*(183+ - everything from the first * literal to the last + literal, and capture group 1 therefore expanded to (106+400)+1*(1822+500)+1*(183

Thursday, November 25, 2021
 
ala
answered 2 Weeks ago
ala
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share