LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Shell script that assign's values to fields (https://www.linuxquestions.org/questions/programming-9/shell-script-that-assigns-values-to-fields-728902/)

NsearchOf 05-27-2009 01:54 PM

Shell script that assign's values to fields
 
In need of help? I need a shell script that will read a line and assign values to each field.
Using /etc/group as an example you have

groupid:x:501:userid,userid,userid

using sed I am able to set the delimiters to a comman value e.g. a comma

Could someone show me how I could use a shell script to read each line and assign a value to each field in that line. I know how to do a fixed or static assignment but since each line in /etc/group will vary on how many fields it has I need to do some kind of loop.

output would maybe look something like this:
f1 f2 f3 f4 f5...


Note: I am VERY new to scripting! So explanations would be GREATLY appreciated.

jan61 05-27-2009 02:09 PM

Moin,

in the case of unknown number of fields you should use an array:
Code:

# redefine Input Field Separator
IFS=':
'
# now : and linefeed are field / record separator
# now read the /etc/group line per line into the array ln
getent group | while read -a ln; do
  # now print each element of the array
  for (( fld = 0; fld < ${#ln[*]}; fld++ )); do
    echo $fld ${ln[$fld]}
  done
done

Jan

NsearchOf 05-28-2009 07:53 AM

Thank you
 
Thank you for your follow up. I do have one question. How to you extract information from the array. Say I wanted info from line 2 field 0 and 3?

ghostdog74 05-28-2009 08:01 AM

you can use awk, which makes manipulating files with fields easier
Code:

awk '{print $1" is column 1, "$2" is column 2 and so on"}' file

theYinYeti 05-28-2009 09:10 AM

Code:

while IFS=: read usr pwd uid gid grp hom shl; do echo "user: $usr - home: $hom"; done </etc/passwd
Yves.

jan61 05-28-2009 02:43 PM

Moin,

that's not difficult:

Code:

# redefine Input Field Separator
IFS=':
'
# line number
lineno=1
# now : and linefeed are field / record separator
# now read the /etc/group line per line into the array ln
getent group | while read -a ln; do
  # access fields 0 and 3 at line 2
  if test $lineno -eq 2; then
    echo "line $lineno: field 0: ${ln[0]}; field 3: ${ln[3]}"
  fi
  # increment line number
  lineno=$((lineno + 1))
done

Jan

NsearchOf 05-29-2009 07:22 AM

Jan61 you have been very helpful
 
Thank you for you help and I hate to keep bothering you. I'm still stuck on this script though. Maybe telling you want the script needs to do will help. I wanted to figure it out myself but sometimes a little help doesn't hurt. I need a script that will look at the /etc/group file and pull the group and the users that are assigned to that group in this format.
group a user1
group a user2
group a user3
group b user1
group b user2

etc...

This is a request someone gave me! Not my idea :(

I like your array idea and I have come close on getting information out but it's the incrementing that doesn't seem to work. Here is what I have so far. It's not pretty.

!/bin/bash
# redefine Input Field Separator
IFS=':,
'
# now : and linefeed are field / record separator
# now read the /etc/group line per line into the array ln
getent group | while read -a ln; do
# now print each element of the array
for (( fld = 0; fld < ${#ln[*]}; fld++ ));
do
x=0
y=3
z="x+2"
who=${ln[x]}
objects=${ln[z]}
echo $who $objects
done
done

The output produces the group and the second field and repeats it for however many fields there are.
I know I must be totally off using the X Y Z variables? Any ideas?

GazL 05-29-2009 09:09 AM

Sometimes a little skulduggery can make the task easier when dealing with shell scripts. In the example below I use tr to convert the ',' to a space so that the for loop works correctly rather than trying to parse around the ','.

Code:

#!/bin/bash

while IFS=: read group password gid user_list
do

  for user in $(echo $user_list | tr ',' ' ')
  do
    echo group $group $user
  done

done < /etc/group


NsearchOf 05-29-2009 10:00 AM

Thanks GazL
 
That seems to work! Any way you can break it down for me? I think I understand almost everything you have done but I'm not sure how you are getting the users? Is it from this statement:
read group password gid user_list
then user_list is seen as one field and then broken up by the tr statement?

GazL 05-29-2009 10:36 AM

The read command will split each line of /etc/group into 4 fields delimited by colon ( because of the IFS=: ) and assign each field to one of the 4 variables listed.

The 4th field user_list will contain a comma separated list of all the users in that group. e.g. "user1,user2,user3"

The for loop is intended to be used to loop through a space separated list of values so without any changes the for would see only a single value and run just once. Within the loop $user would be "user1,user2,user3". Which is not what we want

The tr "," " " will convert
"user1,user2,user3"
to
"user1 user2 user3" which the for loop will then see as 3 separate values to loop through instead of just one.

NsearchOf 05-29-2009 12:04 PM

Thanks again GazL
 
after replying to your last post a did more research on loops. After understanding what the for user in does. Your script made sense. Any scripting sites you recommend for newbies like me?

GazL 05-29-2009 12:28 PM

Quote:

Originally Posted by NsearchOf (Post 3556765)
after replying to your last post a did more research on loops. After understanding what the for user in does. Your script made sense. Any scripting sites you recommend for newbies like me?

Good stuff. :)


I've not really looked at any of them myself in any great detail so its hard to make a recommendation. There's some good stuff on tldp.org. If you google for 'bash tutorial' you'll find more than enough stuff too keep you in reading for a good while.

jan61 05-29-2009 01:03 PM

Moin,

now I got the point ;-) I didn't read your post carefully enough, so I didn't realize, that there's no variable list of fields in your output (the user's list has a different field delimiter than a ":").

The solution of GazL is IMHO the shortest you can get - except one line: I don't like external command calls in a loop ;-)

You can do the user list splitting using bash builtins (parameter expansion) instead of using external tr:

Code:

while IFS=: read group password gid user_list
do
  for user in ${user_list//,/ }
  do
    echo group $group $user
  done
done < /etc/group

Jan

NsearchOf 05-29-2009 01:14 PM

Thanks Jan
 
How would you get the same result using an array?

GazL 05-29-2009 01:19 PM

Quote:

Originally Posted by jan61 (Post 3556830)

The solution of GazL is IMHO the shortest you can get - except one line: I don't like external command calls in a loop ;-)

You can do the user list splitting using bash builtins (parameter expansion) instead of using external tr:

Code:

while IFS=: read group password gid user_list
do
  for user in ${user_list//,/ }
  do
    echo group $group $user
  done
done < /etc/group

Jan


Good point jan. I should have thought of that myself. :)


All times are GMT -5. The time now is 06:47 PM.