I'd like to be able to write a function su_mt_user
that (currently) looks like this:
su_mt_user() {
su someuser -c "$*"
}
The objective is to be able to use it like this:
su_mt_user mt-auth --stuff etc
Which would run the command mt-auth --stuff etc
as user someuser
. The current version works for this particular command, but it fails for commands like this:
some_filename_with_spaces="/home/user/hello there i like spaces in filenames.txt"
su_mt_user stat "$some_filename_with_spaces"
This fails with the following errors:
stat: cannot stat '/home/user/hello': No such file or directory
stat: cannot stat 'there': No such file or directory
stat: cannot stat 'i': No such file or directory
stat: cannot stat 'like': No such file or directory
stat: cannot stat 'spaces': No such file or directory
stat: cannot stat 'in': No such file or directory
stat: cannot stat 'filenames.txt': No such file or directory
I assume that this error happens because even though $some_filename_with_spaces
is properly passed as one argument to the su_mt_user
function, that function expands it to multiple arguments with "$*"
.
I've also tried this, trial-and-error:
su_mt_user() {
su someuser -c "$0 $@"
}
But that fails as well (/usr/bin/stat: cannot execute binary file
(what?))
Of course, stat "$some_filename_with_spaces"
works as expected, from both the current user and the someuser
user.
This looks like some escaping needs to be done, but does bash know how to do that? Does it need manual subtitution? If so, which characters need to be escaped?
Escape characters. Escape characters are used to remove the special meaning from a single character. A non-quoted backslash, \, is used as an escape character in Bash. It preserves the literal value of the next character that follows, with the exception of newline.
bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.
From man bash : -s If the -s option is present, or if no arguments remain after option processing, then commands are read from the standard input. This option allows the positional parameters to be set when invoking an interactive shell. From help set : -e Exit immediately if a command exits with a non-zero status.
In bash ; escape with '\'. You do not need to escape the colon; assuming the variable values are correct, quoting the expansions is the only thing that may make a difference.
To pass multiple arguments through a function to a command, you need "$@"
. "$@"
is special in that even though it's between double quotes, the separate arguments end up in different words, so they're passed down exactly as is. This is different from $@
or $*
without quotes, which would additionally split each argument where it contains whitespace and interpret each resulting word as a glob pattern, and from "$*"
, which coalesces all arguments into a single one with spaces in between.
There's an added wrinkle because su
doesn't directly eat up arguments, they go through a shell. The non-option arguments to su
are passed down as arguments to sh -c
, and you then need an appropriate command for the -c
.
su_mt_user() {
su someuser -c '"$0" "$@"' -- "$@"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With