Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to add a function to my .zshrc that makes adding new USE flags to my /etc/portage/package.use file easier. Normally, I'd have to do

su -c 'echo "net-misc/aria2 bash-completion bittorrent" >> /etc/portage/package.use'

So I tried making a function like

new_use() {
    su -c 'echo "$1" >> /etc/portage/package.use'
}

but then I realized it wouldn't work. I want to know if there's a way of making this function work, or at least if functions are appropriate for this. By the way, I don't mind having to type the root password every time I call the function.

share|improve this question
add comment

3 Answers

up vote 3 down vote accepted

Just reverse the quotes.

new_use() {
    su -c "echo '$1' >> /etc/portage/package.use"
}

This will cause $1 to be expanded before the execution of su.

share|improve this answer
    
Oh, that's exactly what I wanted. Thank you. –  user1002327 Jan 6 '13 at 3:07
2  
This is probably good enough here, but beware that in general, this is unsafe because it allows the caller of the function to execute arbitrary shell commands by passing an argument that contains a single quote (' >/dev/null; echo evilhacker.example.com >>/root/.rhosts; : '). –  Gilles Jan 6 '13 at 21:40
    
@Gilles it requires the root password. –  jordanm Jan 7 '13 at 0:12
2  
@jordanm Which is why it's probably good enough here. But it's not a stretch to extend that to a sudo rule, or to a script that doesn't verify its arguments. Many security holes come from chaining two steps that are safe individually but not in combination. It's better to keep protected at every step. –  Gilles Jan 7 '13 at 0:15
add comment

You can feed stdin to a program with root privileges, like so:

new_use() {
    sudo tee -a /etc/portage/package.use <<< "$1" > /dev/null
}
share|improve this answer
    
Wow, that comes handy. Thanks for the alternate answer! –  user1002327 Jan 6 '13 at 3:08
    
Gotta love unix. I don't think I've ever seen three '<<<' before 8-). –  slm Jan 6 '13 at 3:11
    
@slm, it's a shell feature known as a here string. –  jordanm Jan 6 '13 at 7:20
add comment

The argument of the function is not passed to the underlying shell. You can substitute the argument inside the string that su will pass to the root shell, but beware that the string will be parsed by the root shell, so special characters in it will be expanded. To avoid this extra expansion (which could cause arbitrary code to be executed as root), interpolate the string between single quotes (which causes all characters other than ' to be interpreted literally), and protect single quotes characters in the string ('\'' terminates the string literal, appends a single quote, and starts a new literal, which means that '\'' is effectively a way to put a single quote inside a literal delimited by single quotes).

new_use() {
  su -c "echo '${1//\'/\'\\\'\'}' >> /etc/portage/package.use"
}

Another possible approach is to use tee.

share|improve this answer
    
Very interesting. So that means you can use single quotes inside single quotes, and your function would be used like new_use 'net-misc/aria2 bash-completion bittorrent' instead of using double quotes, right? –  user1002327 Jan 6 '13 at 22:54
    
I don't understand your question. You can “use single quotes inside single quotes”, but the single quote has to be written '\''. What you write is a valid use of the function, but it could equivalently be written new_use "net-misc/aria2 bash-completion bittorrent" or new_use net-misc/aria2\ bash-completion\ bittorrent or many other ways. –  Gilles Jan 6 '13 at 22:59
    
Oh, I know you have to escape them if you want to use single quotes inside single quotes. But then I don't think I understand your answer. What makes it different from the others, besides avoiding the extra expansion? Sorry. bash syntax still manages to confuse me. –  user1002327 Jan 6 '13 at 23:43
    
@user1002327 See my comment under jordanm's answer: the problem is when there's a single quote in the argument. –  Gilles Jan 6 '13 at 23:55
    
Oh, I'm terribly sorry, I hadn't read it before commenting here. Well, the accepted answer is more than enough in this case, but I'll take your advice into account. Didn't know you could do that. –  user1002327 Jan 7 '13 at 0:52
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.