I have to replace a specific line of a file with some other value. for eg: I have a file with content as below:
request.timing=0/10 * * * * * ?
Now, I want to replace 10 (or to be specific, any value in that place) with a dynamic value. Eg, if I want to replace that with 20, the file should be updated as:
request.timing=0/20 * * * * * ?
Can someone help me? I am using sed as below:
sed -i "s/request.timing=0\/??/request.timing=0\/$poller"
where poller is dynamic value we pass.
First of all, you must check the characters the variable $poller has, because sed can interpret any character in there as a special one. Once you have checked that, use a sed separator which is not inside $poller. Let's suppose we can use /:
sed -r 's/(request.timing=0\/)[0-9]{2}/\1'"$poller"'/g'
How does it works
-r option activates extended regular expressions so you can use things like [0-9]{2}, and with ( ... ) you're capturing the string to use in the replacement site.
$ echo 'request.timing=0/10 * * * * * ?' |
sed -r 's:(request.timing=0/)[0-9]+:\1135:'
request.timing=0/135 * * * * * ?
$ poller="135"
$ echo 'request.timing=0/10 * * * * * ?' |
sed -r 's:(request.timing=0/)[0-9]+:\1'"$poller"':'
request.timing=0/135 * * * * * ?
The reason that you were having troubles is that ? is not valid in the regular expression. Use . instead. ? is used to say the previous character may be present 0 or 1 times.
sed -i "s/request.timing=0\/../request.timing=0\/$poller"
(That's not to say the other answers aren't correct!)
Related
I'm trying to append the current date and time to a log file every minute using cron. I want the date and time to be formatted in a specific way.
This works:
* * * * * date >> /home/user/time1.txt
This doesn't:
* * * * * date +%Y%m%d%H%M%S >> /home/user/time2.txt
Any insight is much appreciated!
The problem is that cron treats % as newlines. You need to escape them
From crontab POSIX man page:
Percent-signs (%) in the command, unless escaped with backslash \,
will be changed into newline characters, and all data after the first % will be
sent to the command as standard input.
* * * * * date +\%Y\%m\%d\%H\%M\%S >> /home/user/time2.txt
escape % with \ and then it should work.
This question already has answers here:
How to extract characters between the delimiters using sed?
(2 answers)
Closed 2 years ago.
I would like to remove all the text between the strings /* and */ in a file, where the strings may occur on different lines and surround a comment. For example I would like to remove the following seven lines which are contained between /* and */:
/* "CyIHTAlgorithm.pyx":81
* #cython.wraparound(False)
* #cython.cdivision(True)
* cdef inline object IHTReconstruction2D(fType_t[:,:] data, # <<<<<<<<<<<<<<
* fType_t[:,:] residualFID,
* fType_t[:,:] CS_spectrum,
*/
I have managed to do this using sed where the strings occur on the same line:
sed -i.bak 's/\(\/\*\).*\(\*\/\)/\1\2/' test.txt
but I'm not sure how to extend this to multiple lines in the same file:
I have also tried:
sed -i.bak '/\/\*/{:a;N;/\*\//!ba;s/.*\/\*\|\*\/.*//g}' test.txt following the ideas here (Extract text between two strings on different lines)
This deletes the /* at the beginning and */ but not the intervening text.
Why not to work with sed ranges?
$ cat tmp/file13
first line
/* "CyIHTAlgorithm.pyx":81
* #cython.wraparound(False)
* #cython.cdivision(True)
* cdef inline object IHTReconstruction2D(fType_t[:,:] data, # <<<<<<<<<<<<<<
* fType_t[:,:] residualFID,
* fType_t[:,:] CS_spectrum,
*/
before last line
last line
$ sed '/\/\*/,/\*\//d' tmp/file13
first line
before last line
last line
you can use sed or cut but they are really designed for a pattern so each line should match it.
you should declare first line and last line by getting the lumber line of the start and finish and then you can wrap it into a function.
so,
1) get the line number for /* part
2) get the last line number for */
3) you can use "while read line;" loop and cut every line in between using cut or sed.
awk is really better suited for this kind of things. It supports ranges out of the box with the /pattern/,/pattern2/ syntax.
awk '/[:space:]*\/\*/,/[:space:]*\*\// {next} {print}' file.txt
It works the following way: for the lines between the two patterns it executes {next} actually skipping the line, for everything else it just prints the input.
The following will try to do more, so test first if it fits your needs.
cpp -P test.txt
I found the answer here: https://askubuntu.com/questions/916424/how-to-replace-text-between-two-patterns-on-different-lines
sed -n '1h; 1!H; ${ g; s/<head>.*<\/head>/IF H = 2 THEN\n INSERT FILE 'head.bes'\nEND/p }' myProgram.bes
Notes: This replaces all lines between <head> ... </head> (inclusive) in an HTML document with:
IF H = 1 THEN
INSERT FILE 'head.bes'
END
For example
grep -n 'integer*2' *.f
Shows nothing.But
grep -n '*2' *.f
main.f:57: integer*2 itime(nxmax)
main.f:605: dxy=((xsource(is)-xobs)**2+(ysource(is)-yobs)**2)**.5
main.f:622: chisum=chisum+diff2/uobs**2
model.f:15: integer*2 veli(nxmax)
model.f:52: size2=size**2
time.f:151: integer*2 itime(nxmax)
I really do not understand this.
* is an operator, meaning "match the previous term 0 or more times". So integer*2 matches
intege2
integer2
integerr2
integerrr2
:
none of which appear in your program. * at the beginning of an RE is meaningless (there's no previous term), so is either ignored or treated as match for a *. Escape the * to have it match an actual star:
'integer\*2'
Your grep is using a regex. (Star is being interpreted differently than you might believe). Try
grep -F -n 'integer*2' *.f
Because grep is interpreting the search argument as a regular expression, in which * is meant as "zero or more of the preceding". So 'integer*2 would match intege2 as well as integerrrrr2 since * applies to the preceding r but will not match the literal integer*2.
Escape it with a backslash to interpret it as a literal * and you should get the desired matches:
grep -n 'integer\*2' *.f
What I try to accomplish with 'sed' is to remove a line if the pattern match.
and adding a line if pattern doesn't match.
But how could I make this?
Thanks in advance
Example:
I want this to use this line in Crontab:
*/1 * * * * script 1 test
With a other script I want to remove this line if this pattern is there, and otherwise, if pattern is not matching then add this line.
awk -v tgt='*/1 * * * * script 1 test' 'index($0,tgt){found=1;next} {print} END{if (!found) print tgt}' file
A good practice is to tag your automatically added crontab entries with a comment:
* * * * * script 1 test #projectfoo-testjob
This allows you to easily remove the job:
sed -i.bak '/projectfoo-testjob/d' file
or add it:
grep -q "projectfoo-testjob" file || \
echo '*/1 * * * * script 1 test #projectfoo-testjob' >> file
By tagging the job like this, you prevent duplicates when the user reformats their crontab e.g. to use tabs instead of spaces, and you prevent deleting similar jobs that the user added for themselves.
This might work for you (GNU sed):
sed 'x;/./{x;b};x;/pattern/{h;d};$a\append new line' file
Only append line if not found in file using grep -qF 'line' file && echo 'line' >> file:
grep -qF '*/1 * * * * script 1 test' file || echo '*/1 * * * * script 1 test' >> file
When I read[command] some lines including character '*', it seems that '*' will be looked as a wildcard. whether exsits some solutions leting '*' just be a '*', please!
It depends how you use the variable: if you quote it, filename expansion will not happen. Example:
$ ls
f1 f2 f3
$ read line
*
$ echo "$line"
*
$ echo $line
f1 f2 f3
If you do not want any of the special file name characters to be used as wildcards then enter the following in your script before the read.
set -o noglob
This will prevent the * ? and [] from having special meaning and treat them as normal characters.
The following example demonstrates the point
touch 1 2 3
echo "With wild card expansion"
echo *
echo "Without wild card expansion"
set -o noglob
echo *
And produces the following results
With wild card expansion
1 2 3
Without wild card expansion
*
You can escape it with the escape character: \*. This means the * will be a literal *, not matching one or more characters as the glob pattern.