2

I am re-writing code to work with a newer system. I did not write the original code, but I'm trying to use the old code as a template. When I run the command by itself, it works fine. When I try running it as part of a script or function in the shell, it does not.

#!/bin/bash
function find_user() {
    local txt
    local user_list
    local username
    local displayName

    echo "Find User"
    echo "---------"

    echo -n "Enter search text (e.g: lib): "
    read txt

    if [ -z "$txt" ] || ! validate_fullname "$txt"; then
        echo "Search cancelled."
    else
        echo
        user_list="$(samba-tool user list | grep -i ${txt} | sort)"
        (
            echo "Username Full_Name"
            echo "-------- ---------"
            # Dev Note: Get the username, then displayName parameter, replacing
            # the spaces in displayName with an underscore. Do not need to look
            # for a dollar sign anymore, as computers are not listed as "user"
            # class objects in AD.
            for a in "${user_list[@]}"; do
                username=$a
                displayName="$(
                    samba-tool user show ${a} | grep 'displayName:' | \
                        awk -F: '{gsub(/^[ \t]+/,"""",$2); gsub(/ ./,""_"",$3); print $2}' | \
                        tr ' ' '_')"
                echo "${username} ${displayName}"
            done
        )| column -t
     fi
}

When I try to run it, and enter the find_user function, it prompts for the search text (i.e. I can type js) and press Enter.

My issue is with the $displayName= part. It seems to generate an empty string when running in the script. If I run the command manually from the terminal (filling in, for example, jsmith as a substitute for ${a}), it outputs the full name correctly.

My system is running bash.

What is going on, and how can I fix this?

  • Edit question to show first line of script (#!…), and to show how you call find_user. – ctrl-alt-delor Jun 24 at 21:46
  • @ctrl-alt-delor Is that acceptable? It's part of a much larger script. I am calling the script as a test by copying and pasting the function into a bash shell, and typing find_user to start it – Canadian Luke Jun 24 at 21:57
  • That is not a good question title because you do not run the same code in an interactive shell and in a script. If you had replaced $a with jsmith in the script, then the script would have worked, too. – Hauke Laging Jun 24 at 22:10
  • @HaukeLaging Suggestion on what I could say for the title? – Canadian Luke Jun 24 at 22:19
  • Perhaps something like array access does not work as expected – Hauke Laging Jun 24 at 22:23
5

The problem is that user_list is accessed as an array

for a in "${user_list[@]}"

but set as a string:

user_list="$(samba-tool user list | grep -i ${txt} | sort)"

Instead you need

IFS=$'\n'     # split on newline characters
set -o noglob # disable globbing

# assign the users to the array using the split+glob operator
# (implicitly invoked in bash when you leave a command substitution
# unquoted in list context):
user_list=( $(samba-tool user list | grep -ie "${txt}" | sort) )

Or better (though bash-specific):

readarray -t user_list < <(samba-tool user list)

(note that that one would create one empty element for each empty line of the input if any, contrary to the split+glob approach which would discard empty lines).

| improve this answer | |
  • That worked! Thank you! Is there a decent reference to explain why I need to use the extra parenthesis? – Canadian Luke Jun 24 at 22:18
  • @CanadianLuke That's just how arrays are defined. See the block Arrays in man bash. foo=(a b c) / foo=( $(echo a b c) ) – Hauke Laging Jun 24 at 22:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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