gremo
gremo

Reputation: 48487

Why sed is duplicating the first added line (sending the sed output to the same file)?

Starting file (/etc/crontabs/root):

# do daily/weekly/monthly maintenance
# min   hour    day     month   weekday command
*/15    *       *       *       *       run-parts /etc/periodic/15min  
0       *       *       *       *       run-parts /etc/periodic/hourly 
0       2       *       *       *       run-parts /etc/periodic/daily  
0       3       *       *       6       run-parts /etc/periodic/weekly 
0       5       1       *       *       run-parts /etc/periodic/monthly

I want to replicate this file, remove comments... and adding the content to the same file, so I run:

sed '/^#/ d; s/\/etc/\/root\/etc/' /etc/crontabs/root >> /etc/crontabs/root

... which should remove all comments, replace /etc with /etc/root... and add the result to the same file.

Wrong output (please note the "extra" line starting with */15):

# do daily/weekly/monthly maintenance
# min   hour    day     month   weekday command
*/15    *       *       *       *       run-parts /etc/periodic/15min
0       *       *       *       *       run-parts /etc/periodic/hourly
0       2       *       *       *       run-parts /etc/periodic/daily
0       3       *       *       6       run-parts /etc/periodic/weekly
0       5       1       *       *       run-parts /etc/periodic/monthly        

*/15    *       *       *       *       run-parts /root/etc/periodic/15min     
0       *       *       *       *       run-parts /root/etc/periodic/hourly    
0       2       *       *       *       run-parts /root/etc/periodic/daily     
0       3       *       *       6       run-parts /root/etc/periodic/weekly    
0       5       1       *       *       run-parts /root/etc/periodic/monthly   

*/15    *       *       *       *       run-parts /root/root/etc/periodic/15min

Expected/wanted output:

# do daily/weekly/monthly maintenance
# min   hour    day     month   weekday command
*/15    *       *       *       *       run-parts /etc/periodic/15min
0       *       *       *       *       run-parts /etc/periodic/hourly
0       2       *       *       *       run-parts /etc/periodic/daily
0       3       *       *       6       run-parts /etc/periodic/weekly
0       5       1       *       *       run-parts /etc/periodic/monthly        

*/15    *       *       *       *       run-parts /root/etc/periodic/15min     
0       *       *       *       *       run-parts /root/etc/periodic/hourly    
0       2       *       *       *       run-parts /root/etc/periodic/daily     
0       3       *       *       6       run-parts /root/etc/periodic/weekly    
0       5       1       *       *       run-parts /root/etc/periodic/monthly   

Ideas?

Upvotes: 0

Views: 44

Answers (2)

Shawn
Shawn

Reputation: 52674

If you want a one liner, it's fairly straightfoward using ed:

printf "%s\n" ka '1,$t' "'a,\$g/^#/d" "'a+1,\$s/\/etc/\/root\/etc/" w | ed -s /etc/crontabs/root

or a bit easier to read using a heredoc:

ed -s /etc/crontabs/root <<'EOF'
ka
1,$t
'a,$g/^#/d
'a+1,$s/\/etc/\/root\/etc/
w
EOF

Upvotes: 1

Barmar
Barmar

Reputation: 782785

You shouldn't write out to the same file that you're reading from. It will read the lines that you added to the file, and continue processing them. So when it gets to the lines with /root/etc, it will replace the /etc in that, producing /root/root/etc. It could conceivably get stuck in an infinite loop, since it keeps extending the file and will never reach the end.

What you can do is copy the crontab file to a new file, then use sed to append to that.

cp /etc/crontabs/root /tmp/new_crontab
sed '/^#/ d; s/\/etc/\/root\/etc/' /etc/crontabs/root >> /tmp/new_crontab
cp /tmp/new_crontab /etc/crontabs/root

Upvotes: 2

Related Questions