Need bash script help

znilsson
Contributor II

I hate being such a script noob. I feel like I'm really close but am missing some critical piece of information in order to get this script to work. This script is intended to get the name of the current user and then make that user an admin, or make them a standard user, depending on whether I have the -d or -a in there.

I can get the first line to return the user name on its own, and I can get the second line to set or remove the user as an admin as long as I put the name in rather than using a variable, so I know I'm close. I just can't get the two lines to work together, i.e. to get the first line to grab the username, set it as the "userName" variable, and pass it to the second line via $userName.

#!/bin/sh
userName=ls -l /dev/console | awk '{ print $3 }'
sudo dseditgroup -o edit -a $userName -t user admin

Searching for how to create functional variables hasn't turned up anything relatable to what I'm doing here. Anybody have some pointers on how to make this work?

1 ACCEPTED SOLUTION

Nix4Life
Valued Contributor

@znilsson looks llike you are missing the ticks. try this:

#!/bin/sh
userName=`ls -l /dev/console | awk '{ print $3 }'`

it's the character below the tilde. "~"

Larry

View solution in original post

17 REPLIES 17

Nix4Life
Valued Contributor

@znilsson looks llike you are missing the ticks. try this:

#!/bin/sh
userName=`ls -l /dev/console | awk '{ print $3 }'`

it's the character below the tilde. "~"

Larry

macbentosh
New Contributor III

Try this for getting the user name.

Sometimes you can just use $3

#!/bin/sh
loggedInUser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'`
dseditgroup -o edit -a $loggedInUser -t user admin

znilsson
Contributor II

@LSinNY That was exactly it. Man, I knew I was close, I just didn't know what to look for. It works perfectly now, thanks.

@macbentosh Thanks, sorry I didn't try your solution only because I tried Larry's first and it worked, I was just missing the ticks.

Thanks to both of you for your time, I really appreciate it.

donmontalvo
Esteemed Contributor III

@macbentosh this is the first time I've seen this:

python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'

Is there any benefit to using this command, over the command we've been using:

ls -l /dev/console | awk '{ print $3 }'

Just curious, since the later seems faster:

$ time python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'
donmontalvo

real    0m0.113s
user    0m0.083s
sys 0m0.024s
$ time ls -l /dev/console | awk '{ print $3 }'
jdoe

real    0m0.007s
user    0m0.002s
sys 0m0.004s
$
--
https://donmontalvo.com

bentoms
Release Candidate Programs Tester

@donmontalvo it's mine & Frogors fault.

See this post

Incidentally, I need to update the bit about FUS. As others have not seen an issue with the other methods.

Only really difference is that in the post there's an Apple link that gives the Python method more of a look of approval from Apple.

brock_walters
Contributor
Contributor

Hi guys -

+1 on @macbentosh comment. Also, @donmontalvo parsing the output of

ls

can generate unpredictable results. Here are some examples:

http://mywiki.wooledge.org/ParsingLs

Wanted to point out another option as well:

Sometimes the backtick character

`somecommandsthatdosomethinghere`

is needed when you are effectively running multiple commands together on 1 line (although, if you are, there is probably, but not always, another way to do what you're trying to do...)

What you see recommended most often for something like what's posted above, i.e., for running a command to generate output as a variable value, is the "Command Substitution" syntax instead of backticks:

userName=$(ls -l /dev/console | awk '{ print $3 }')

Thanks!

macbentosh
New Contributor III

@bentoms So I need to switch it up?

sean
Valued Contributor

@brock.walters parsing ls in this context isn't an issue. The name of the file is fixed and so the issues with parsing ls aren't applicable. That said, why pipe when you can just use stat.

stat -f%Su /dev/console

As for the 'recommended' way. I've never switched to it, as Apple clearly indicate "Because of these issues, routines like SCDynamicStoreCopyConsoleUser exist only for compatibility purposes. It's likely that they will be formally deprecated in a future version of Mac OS X." Read the caveats, which apply to the ownership of /dev/console as well.

/dev/console only becomes an issue if you allow multiple logins: fast user switching, remote console users.

The issue is that only one /dev/console can exist and the ownership of this file changes to the last person to login into a loginwindow session. Who is you script trying to affect, the person with actual keyboard and mouse or any user with a loginwindow session?

For example, the below shows two loginwindow processes; two remote console users. In the current state of this machine, /dev/console happens to belong to user that doesn't own the process "loginwindow console", whilst "loginwindow console" happens to belong to the first user logged in.

$ pgrep -xl "loginwindow"
473 loginwindow
30369 loginwindow

$ pgrep -fx "/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow console"
473
$ pgrep -fx "/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow"
30369

and in fact, running the python method reported the owner of /dev/console anyway.

So if you are happy that you only have one user with a loginwindow session on any machine at any one time, fill you boots with /dev/console! If you do have multiple users, you may wish to check which processes are running and perhaps get all of the users and not just one.

#!/bin/bash

pgrep -x "loginwindow" | while read line
do
    current_user=`ps -p $line -ouser=`
    echo $current_user
done

exit 0

brock_walters
Contributor
Contributor

Hi @sean

I would respectfully disagree.

The beauty of being an administrator of a fleet of computers is that you know (hopefully) how they were setup. The beauty of bash scripts is that you can get whatever information you like and use whatever method you like that is returning the results you need.

None of that changes the fact that the output of ls can generate strange results. Using its output in a script is simply not considered a best practice which is my only concern. It's not necessarily wrong.

As an example, many people use bash aliases for ls so that the ls flags can be used without having to type them every time. Unless you are also deploying a custom .bash_profile to your users this alone could cause problems for the types of scripts I see often on JAMF Nation that use the output of ls. Of course there are ways to handle this problem. :)

This isn't (to me) a contest. I just like to put the information I've found concerning best practices here because many other people seem to not have found it elsewhere. Thanks for your input & lets keep the conversation going!

sean
Valued Contributor

@brock.walters I completely agree with what you are saying regarding the issues with ls within scripts, but in this particular instance the pitfalls of ls will never be experienced, so no harm would be done using it here.

/dev/console is not going to suddenly have strange characters or newlines, it is what it is and ls is being used to call this exact, precisely named file.

The issue with ls is when you are calling directories of files, that could potentially have other characters, to get a list, only to find your list is not as expected and ruins your script or perhaps worse.

The point is, care should be taken where you choose to use this method, which is worth highlighting, but I was just easing anyone's concern who may already be using ls for this particular use, as they needn't panic and rewrite this script, since it will work as hoped and the ls parse issues are not of concern here.

brock_walters
Contributor
Contributor

Hi @sean

Right on - I think we're on the same page here. I should have been more careful about the specifics of the post versus the more general point I was trying to make. Don's question felt general to me so I answered it in that way.

I am going to post some additional options for getting logged in user later on this thread: they may not always get the result you need but my view is it's better to have options.

Lastly, I just want to make clear that I'm not the Grand Puba, All-Knowing master of anything. :) I'm just a guy that's made lots of goofy mistakes in scripts & I want to help others (especially on this forum) past some of those mistakes when I can. Thanks!

donmontalvo
Esteemed Contributor III

@brock.walters wtote:

Lastly, I just want to make clear that I'm not the Grand Puba, All-Knowing master of anything. :) I'm just a guy that's made lots of goofy mistakes in scripts & I want to help others (especially on this forum) past some of those mistakes when I can. Thanks!

@NateW once told me: "if the script you wrote a year ago isn't stupid today, you aren't learning". ;)

--
https://donmontalvo.com

sean
Valued Contributor

If anyone says that they are the All Knowing of anything, they don't realise how much they don't know!

brock_walters
Contributor
Contributor

I don't know @donmontalvo some of mine from last year are
pretty great. :)

bentoms
Release Candidate Programs Tester

If you really want to know if stuff is stupid time later, blog it.

Just saying from experience. :)

donmontalvo
Esteemed Contributor III

Future Self824c046bc1b54b278bfc75c3a7dab505

--
https://donmontalvo.com

zetaomegagon
New Contributor III

FYI everyone.

Backticks are deprecated syntax. I know that OSX doesn't ship with the latest bash, but admins could be using MacPorts (I do).

The proper syntax is:

VAR=$(command arg1 argN)

EDIT: oops! did not see @brock.walters post. I just have to say something when I see deprecated syntax. Anyway, I'll leave these here:

EDIT2: also

w | grep -v grep | grep 'console' | awk '{ print $1 }'