Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash: pass "$@" argument with empty variables to sudo -i

I have a function that discards the current environment and runs a script as a freshly login:

# Recieves a username, a script path and the arguments of the script
run_in_new_login() {
    local user
    local script

    user=$1
    script=$2

    shift 2

    sudo -i -u "${user}" -H bash "${script}" "$@"  # LOST
}

The problem with this function is that if it receives empty arguments, that argument is discarded. Example:

#! /usr/bin/env bash
# ~/print_n_args.sh

echo "Recieved $# arguments"
param3=hello
param4="last_one_detected"
param5=""
param6=""

run_in_new_login ${USER} print_n_args.sh param1 param2 "${param3}" "${param4}" "${param5}" "${param6}"
> Recieved 4 arguments

These parameters are lost on line LOST, because if I print the number of arguments before and after the shift, the number of reported arguments are 8 and 6, respectively.

Is there a way of passing them as empty arguments? (just as the function itself can receive them).


PS: I'm fully aware that for this case in particular I could just use sudo instead of my function and be done with it. But I'm interested in the general case script -> function -> script argument passing when there are empty arguments. Nevermind, using sudo without the function has the same problem.


 EDIT

Doing more testing I've found out that is actually a sudo problem:

sudo -u ${USER} -i -H bash print_n_args.sh param1 param2 "${param3}" "${param4}" "${param5}" "${param6}"
> Recieved 4 parameters

bash print_n_args.sh param1 param2 "${param3}" "${param4}" "${param5}" "${param6}"
> Recieved 6 parameters

The problem with my function is that sudo is removing the empty variables. Is there a way to tell sudo keep the empty arguments?

like image 241
jabozzo Avatar asked Feb 18 '26 01:02

jabozzo


1 Answers

 It's a Bug

Source: https://bugzilla.sudo.ws/show_bug.cgi?id=679

Workaround: Passing empty arguments to sudo -i


In the meantime, for my case, this smelly code will have to do:

# Recieves a username, a filepath and the arguments to the script
run_in_new_login() {
    if [ "$#" -lt "2" ]; then
        log_error "Not enough arguments to run_in_new_login"
        return 1
    fi

    local user
    local script
    local command_
    local escaped

    user=$1
    script=$2

    shift 2

    command_="${script}"

    for val in "$@"; do
        escaped="$(sed 's/"/\\"/g' <<<"${val}")"
        command_="${command_} \"${escaped}\""
    done

    sudo -i -u "${user}" -H bash -c "${SHELL} ${command_}"
}

It basically iterates through all arguments. For each, expands the argument, double quotes them escaping any double quote inside the argument value and concatenates them in a single string to be run with bash -c. Not suitable for scripts that internally expands arguments.

like image 176
jabozzo Avatar answered Feb 19 '26 19:02

jabozzo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!