Industry guru Dave Taylor offers tech support on technical and business topics, including iPhone, iPod, Microsoft Windows, Sony PSP, cellphones, online advertising, CSS, Web design, business, Unix, Linux, SEO, Mac OS X, and shell script programming.     


Parsing "id" strings in a Shell Script?

Hello Dave. I need a Bash shell script that creates a directories with the group names automatically when user logs in to the system, in their home directory.

For example, user "sandy" might have the following set of groups from the 'id' command:

uid=10002(sandy) gid=119(rtkit) groups=119(rtkit),10001(admin),10003(pr007drdl)

and the directories "rtkit", "admin" and "pr007drdl" should then be created. How do I do it?


Dave's Answer:

I think this falls into the category of "Dave, can you do my homework?" but since it's an interesting problem, I'll spend some time talking about how to do this sort of simple parsing and then wrap it with with a 'for' loop that steps through each value.

There are also nuances to your assignment that are important. For example, trying to create a directory that already exists is sloppy and poor coding, so part of what you need to do is test for the existence of the group subdirectory prior to requesting its creation. Sure you can use a "force" flag or an "ignore error" flag on the call to 'mkdir', but that's cheap coding and if we're going to write something, let's write it well, right?

So here's the basic approach I'm envisioning: in the .login file extract one or more group names from the output of the 'id' command. For each value test to see if it exists yet as a subdirectory. If it does, move to the next value. If it doesn't, create it.

Let's see how that looks as a script.

The first step is to break down the 'id' string into the individual group elements. If you look at the output of "id", you'll see that there's a regular pattern to the results, so it's not too bad. Here's the output of my own id string:

uid=501(taylor) gid=20(staff) groups=20(staff),401(com.apple.access_screensharing),404(com.apple.sharepoint.group.3), 402(com.apple.sharepoint.group.1),403(com.apple.sharepoint.group.2),12(everyone),33(_appstore),61(localaccounts), 79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),100(_lpoperator),204(_developer)

Kind of crazy complicated, but it's still three fields separated by spaces, the third of which is of the form groups=NUMBER(name),NUMBER(name), etc. So my approach to this is to first jettison the uid and gid values. That looks like this:

id | cut -d\ -f3

The '-d' flag to cut specifies the delimiter that separates fields, then '-f3' says we're only interested in the third field, the group list.

When run, it produces something like this:

groups=20(staff),401(com.apple.access_screensharing),404(com.apple.sharepoint.group.3), 402(com.apple.sharepoint.group.1),403(com.apple.sharepoint.group.2),12(everyone),33(_appstore),61(localaccounts), 79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),100(_lpoperator),204(_developer)

To break it up further, I'm going to use 'tr' to translate all open parens into carriage returns, essentially turning this one long line into a lot of very short lines:

$ id | cut -d\ -f3 | tr '(' '\n'
groups=20
staff),401
com.apple.access_screensharing),404
com.apple.sharepoint.group.3),402
com.apple.sharepoint.group.1),403
com.apple.sharepoint.group.2),12
everyone),33
_appstore),61
localaccounts),79
_appserverusr),80
admin),81
_appserveradm),98
_lpadmin),100
_lpoperator),204
_developer)

Two things left: we need to remove everything after the closing paren (which we can do with another invocation of the 'cut' command) and we need to remove the groups=20 line at the very beginning. String it all together and here's what we have:

$ id | cut -d\ -f3 | tr '(' '\n' | cut -d\) -f1 | grep -v '='
staff
com.apple.access_screensharing
com.apple.sharepoint.group.3
com.apple.sharepoint.group.1
com.apple.sharepoint.group.2
everyone
_appstore
localaccounts
_appserverusr
admin
_appserveradm
_lpadmin
_lpoperator
_developer

With that done, the rest is a breeze, we just wrap it with a 'for' loop:

for groupname in $(id | cut -d\ -f3 | tr '(' '\n' | cut -d\) -f1 | grep -v '=' )
do
  if [ ! -d $groupname ] ; then
    mkdir $groupname
  fi
done

That's your code snippet. In my case, it'd be easy to add a filter that would, for example, skip any groupname that started with an underscore or contained a dot, but I'll leave that as an exercise for the reader.


More Useful Shell Script Programming Articles:
✔   Secretly capture screenshots on my Mac?
When I used to work on a Linux system, there was a utility we had that would let me take screen captures every...
✔   Parsing "id" strings in a Shell Script?
Hello Dave. I need a Bash shell script that creates a directories with the group names automatically when user logs in to the...
✔   Copy and Paste from the Mac OS X Command Line?
I am constantly running commands in Terminal.app on my MacBook and then copying and pasting the results into email messages or documents. Yes,...
✔   Script to test line lengths for Twitter compatibility?
I've been tasked with writing a series of tweets for a Black Friday marketing campaign and am finding it a bit tricky because...
✔   Shell script to convert lowercase to title case?
As part of a project I'm working on, I find myself deep in a Linux shell script, needing to have a subroutine that...

Let's stay in touch!
Sign up for my weekly AskDaveTaylor Newsletter and you'll receive even more tech and gadget help right to your inbox, along with exclusive news and industry updates. It's good stuff. I promise!
    Enter your name: and your email addr:  





Categorized: Shell Script Programming   (Article 10217, Written by )
Tagged: bash script, bash shell script, group management, linux, script programming
Previous: How do I create a new Aperture library on my Mac?
Next: How do I copy voice memos off my iPhone 4s?




Check This Out Too...

 
Look for Answers
Need Help? Ask Dave Taylor!


Follow Me on Pinterest

Find Me on Google+
ADT on G+
© 2002 - 2013 by Dave Taylor. All Rights Reserved.

Note: This web site is for the purpose of disseminating information for educational purposes, free of charge, for the benefit of all visitors. We take great care to provide quality information. However, we do not guarantee, and accept no legal liability whatsoever arising from or connected to, the accuracy, reliability, currency or completeness of any material contained on this web site or on any linked site. Further, please note that by submitting a question or comment you're agreeing to my terms of service, which are: you relinquish any subsequent rights of ownership to your material by submitting it on this site. My lawyer says "Thanks".
"Ask Dave Taylor®" is a registered trademark of Intuitive Systems, LLC.