1

I have a sed command within a bash script that replaces the 10th line in a file with the value of a variable. Ok to stop confustion (this is my fault, here is the complete script:

#!/bin/bash

#Sync timezone between system and php

##get current timezone of system
line=$(head -n 1 /etc/sysconfig/clock)    
timezone=${line:6}

##Set up php date string
time="date_default_timezone_set('${timezone%?}');"
sed -i 10s|.*|$time| test.php

so time would have a value like:

date_default_timezone_set('Europe/London')

Now gives these errors:

> test.php: Permission denied
> date_default_timezone_set('Europe/London);: Not such file or direcotry
> .: .:: is a directory
> sed: -e expression #1. char 3: unterminated 's' command

Any help would be great, and if you need any more info let me know!

DevWithZachary
  • 3,545
  • 11
  • 49
  • 101
  • That will replace the whole line with `$time`. Don't you just want to replace part of the line, such as `$timezone`? – Zenexer May 03 '13 at 19:13
  • Yes another option would be to keep the line in test.php and just update the part that is $timezone. I was not sure how to do that so just did the whole line, but if you can do that, that would be great – DevWithZachary May 03 '13 at 19:14
  • This will replace the entire line with `$time`. You will have a line in your PHP file with just `$time`. Generally, that's invalid PHP. --Oh wait, I see... – Zenexer May 03 '13 at 19:15
  • Yes the php file line 10 is just $time this does work for my purpose – DevWithZachary May 03 '13 at 19:17
  • I was thinking that $time is a PHP variable, but it's a bash variable... never mind. – Zenexer May 03 '13 at 19:17
  • I believe the issue is that the `/` character appears in the value of the `$time` variable. You probably need to escape that, so that sed doesn't get confused. – Jonah Bishop May 03 '13 at 19:18
  • `|` is the "pipe" character, so you should use something that's not special for the shell. My answer uses `@`, which should work. You could use `|` too but then you have to make sure you get your quoting/escaping correct. – Alok Singhal May 03 '13 at 20:31

3 Answers3

1
time='date_default_timezone_set\("\$timezone"\);'

Note that I reversed the style of quotes, as well. That's necessary because PHP won't substitute the variable when using single quotes.

You could also enclose $time in quotes, but if $timezone is an actual variable, you still need double quotes:

time='date_default_timezone_set("$timezone");'
sed -i 10s/.*/"$time"/ test.php

Based on your update to the question, my understanding is that you are actually using a string constant in place of $timezone, so this might not be applicable. In this case, the cleanest option is to do:

time='date_default_timezone_set("America/New_York");'
sed -i 10s/.*/"${time/\//\\/}"/ test.php

Note that this requires bash to be in "bash" mode, as opposed to "sh" mode. Ensure that you have #!/bin/bash at the top of any scripts.

Zenexer
  • 18,788
  • 9
  • 71
  • 77
  • hm. i got strange error: `sed: 1: "test.php": undefined label 'est.php'` by running the above code – kobame May 03 '13 at 19:43
  • @kobame Which set of code? All of it works for me. – Zenexer May 03 '13 at 19:48
  • the last two lines, with the `sed -i 10s/.*/"${time/\//\\/}"/ test.php` - i put both into a file myscript and executed as `bash myscript` - my test.php contains only 20 lines of numbers – kobame May 03 '13 at 20:07
  • nah - just fugured out - need GNU sed - with the normal POSIX sed the script not working. when tried it with my `gsed` what is the gnu sed it works. Can you write it please POSIX compatible? – kobame May 03 '13 at 20:09
  • This should be POSIX-compatible; it's a pretty basic sed script. The only thing that might not be POSIX-compatible is the quoting, which means that you would have to rely on the very first method, where everything is pre-escaped. You'd have to check on that, though, as I don't know for sure. – Zenexer May 03 '13 at 20:15
  • That being said, there's nothing in here that looks like a sed label. Are you sure that you aren't using the answer with the colons? That is quite possibly POSIX-incompatible, and if it is, it could give you that very error. – Zenexer May 03 '13 at 20:17
  • no, im using the two lines from your last example as quoted above. It is simple not working. – kobame May 03 '13 at 20:18
  • That sounds like a bug, because there are no colons in that. – Zenexer May 03 '13 at 20:19
  • 1
    Zenexer and @kobame - BSD sed (incl. on macs) requires an argument to `-i`, specifying the backup suffix, so it's taking the `10s/.../` as that argument, leaving `test.php` as the command; the first `t` of that is being interpreted as a jump command to the label `est.php`, which doesn't exist, causing the error you are encountering. You can fix this by changing the `-i` to `-i .bak` or `-i ''`. – Kevin May 03 '13 at 21:36
1

For getting timezone is unfortunately not portable, but usually the /etc/localtime is an symbolic link to your timezone, so you can:

tz=$(readlink /etc/localtime | sed 's:\(.*\)/\([^/]*\)/\([^/]*\)$:\2/\3:')
echo ==$tz==

you will get your something like ==Europe/London==. Now you can construct your string

time="date_default_timezone_set('$tz');"

and use it in the sed - but dont use / as delimiter (because the time sting containing it and confusing your sed)

sed -i "10s:.*:$time:" test.php
clt60
  • 62,119
  • 17
  • 107
  • 194
  • And what happens if your string changes to have a colon in it? – Zenexer May 03 '13 at 19:32
  • But theoretically, as code changes, it's possible that someone might add that character. It's generally a better idea to escape everything. – Zenexer May 03 '13 at 19:35
0

Since timezone contains / character, you need to do something special:

sed -i 10s@.*@$time@ test.php

You can use any character that doesn't appear in your source and destination strings. Here I chose @.

Alok Singhal
  • 93,253
  • 21
  • 125
  • 158