0

my main intense is to to extract only user name from the/etc/passwd file and store then in array list i can display them one by one for this i have created simple script as below

#!/bin/bash


cat "/etc/passwd" > OUTPUT

echo -e $OUTPUT
IFS=:
read -ra ADDR <<< "$OUTPUT"

for i in "${ADDR[@]}"; do
    echo -e $i
done

And the output of

>    cat /etc/passwd

   root:$1$L15vXdMd$SVx9qKAzHtLcqGN8n2SIc.:0:0:root:/:/bin/sh
   sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/bin/false
   super:x:1111:1100:Ldap user:/opt/www/usr/super:/bin/sh
   admin:x:1107:1100:Ldap user:/opt/www/usr/admin:/opt/www/jv/bin/cliInit.sh
   guest:x:1101:1100:Ldap user:/opt/www/usr/guest:/opt/www/jv/bin/cliInit.sh
   postgres:x:1000:1000:Linux User,,,:/home/postgres:/bin/sh
   albert:x:1114:1100:Ldap user:/opt/wwwl/usr/albert:/opt/www/jv/bin/cliInit.sh
   ritesh112:x:1125:1001:RADIUS user:/opt/www/usr/ritesh112:/opt/dell/mc/bin/cliInit.sh

might be i am doing wrong way(that's why i ask the question) in above script.As per my logic first redirect the /etc/passwd to any variable by (cat "/etc/passwd" > OUTPUT don't know it right or wrong Also as alternative have tried read -ra ADDR <<< "cat /etc/passwd" but not working ) then separate the output by IFS=: bash variable and store all username in array ADDR.

i expect the output of script as follow except sshd and postgres user names.

root
super
admin
guest
albert
ritesh112

But it not working any one have idea?

Jayesh Bhoi
  • 24,694
  • 15
  • 58
  • 73

6 Answers6

4
cat "/etc/passwd" > OUTPUT

Does not create a variable, it just copies the /etc/passwd to a file named OUTPUT. To get the contents into a variable you can try OUTPUT=$(cat /etc/passwd).

But you can simply use cut:

cut -d: -f1 /etc/passwd
perreal
  • 94,503
  • 21
  • 155
  • 181
2

You could try something like :

declare -a array
i=0
cut -d: -f1 /etc/passwd|egrep -v "^(sshd|postgres)$"|while read; do
    array[$i]="$REPLY"
    i=$((i + 1))
done
echo "${array[@]}"

Or something like :

declare -a array
i=0
while read; do
    array[$i]="$REPLY"
    i=$((i + 1))
done <<< "$(cut -d: -f1 /etc/passwd|egrep -v '^(sshd|postgres)$')"
echo "${array[@]}"

Or :

declare -a array
i=0
while read; do
    array[$i]="$REPLY"
    i=$((i + 1))
done < <(cut -d: -f1 /etc/passwd|egrep -v '^(sshd|postgres)$')
echo "${array[@]}"

Otherwise, you could use awk too instead of cut and egrep (the both) :

awk -F":" '($1 != "sshd" && $1 != "postgres"){print $1}' /etc/passwd|while read; do
    #...
done
Idriss Neumann
  • 3,760
  • 2
  • 23
  • 32
2

As nobody else seems to be putting the results in an array like you asked, I'll offer this:

declare -a array=($(awk -F: '!/^sshd|^postgres/{print $1}' /etc/passwd))
echo ${array[1]}
root
echo ${array[2]}
daemon
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
1

With a little of awk, you can reach your goal with

i=0
awk -F:  '{ print $1 }' /etc/passwd | egrep -v '^(sshd|postgres)$' |while read; do
    array[i]=$REPLY
    i=$((i + 1))
done

#output 5th item in array 
echo ${array[4]}
#output array length
echo ${#array[*]}
epsilon
  • 2,849
  • 16
  • 23
  • thanks for help...it also display `sshd` and `postgres` which not require and also how to store list of users in array – Jayesh Bhoi Feb 03 '14 at 09:09
  • 1
    Never use `for i in $(cmd)`. You could see this answer for more details : http://stackoverflow.com/questions/19606864/ffmpeg-in-a-bash-pipe/19607361?stw=2#19607361 And using `cut` instead of `awk` is enough in this case (no need to use a tank to kill a fly). – Idriss Neumann Feb 03 '14 at 09:21
1

@perreal already explained what's wrong with your script. Here is what I would do:

cut -d: -f1 /etc/passwd | egrep -v '^(sshd|postgres)$'

Explanation:

cut prints fields of the input. -d: says fields are delimited with :, -f1 selects the first field.

egrep filters the output of cut further. -v says "print anything that doesn't match" and the regular expression matches exactly two user names. So it would still print sshd2 or postgresadmin.

To put everything into an array:

declare -a array=($(cut -d: -f1 /etc/passwd | egrep -v '^(sshd|postgres)$'))

(note: BASH syntax; other shells work slightly different).

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
1

Don't store the output in an variable/array (you can get all sorts of buffering issues in some cases--although not with /etc/passwd, and there's simply no need), just do something like parsing it line by line or use a tool like or as perreal suggested

e.g.

#!/bin/bash

while read -r line; do 
  echo "${line%%:*}"
done < /etc/passwd

${line%%:*} will remove remove the longest suffix matching :*, meaning everything after and including the first :

To get an array, you can just change it to (also note not including postgres and sshd in array. Number of ways to do this, but this should be good enough here)

#!/bin/bash

while read -r line; do
  [[ "${line%%:*}" != postgres && "${line%%:*}" != sshd ]] && arr+=("${line%%:*}")
done < /etc/passwd

for i in "${arr[@]}"; do
  echo -e "$i"
done

Or do something like command substitution (but again, not the best practice in most cases)

IFS=$'\n'
arr=($(< /etc/passwd))
Community
  • 1
  • 1
Reinstate Monica Please
  • 11,123
  • 3
  • 27
  • 48
  • ok that's true but it parse usrname for only display purpose but what i require later i interested to use array of user name list. – Jayesh Bhoi Feb 03 '14 at 09:22
  • ohh..great but please except `sshd` and `postgres` username from array list so my job will done. – Jayesh Bhoi Feb 03 '14 at 09:36