Linux - SoftwareThis forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
The below coding is to find who are all the user having home directory
for (( a=1; a<=$#; a++ ))
do
ls /home | grep $$a >>/dev/null
if [[ $? -eq 0 ]]
then
echo $$a is having home dir
else
echo $$a is not having home dir
fi
done
Note: Here i am trying to pass usernames as a parameter.
Output:
6712a is having home dir
Issue:
$$a is not taking my parameter value. it is taking $$ as a process ID (6712). I want to check $1, $2, $3, etc using $$a. I tried by using brace like $($a), ${$a}, etc. But it is not working. Kindly help me to resolve this issue.
It took me a while to understand what you were trying to accomplish with that for loop, but I think I get it now: You want the loop to iterate though the command line parameters, and then refer to a specific parameter variable, say "$1", inside the loop using a syntax like $${a}, am I right?
The problem is related to the way parameters are expanded. You want "$${a}" to expand to something like "$1" or "$2" initially, with 1 or 2 being the value of $a, and then you want the shell to expand the actual parameter variable ($1 or $2, depending on the value of $a). As you've seen, that's doesn't work.
While some clever coding using delayed expansion might work, may a suggest an alternative approach? How about focusing on $1 and then use shift to iterate through the command line arguments? Just create a loop that runs while $1 is non-null, and inside that loop, check for the existence of a home directory and run shift at the end:
Code:
while ! [ "$1" == "" ]; do
if [ -d /home/$1 ]; then
echo $1 has a home directory
else
echo $1 does not have a home directory
fi
shift
done
(I replaced your "ls dir, pipe to grep, check exit code" test with if [ -d dir ], as that's much less likely to return a false positive.)
This way, you'll be able to handle any number of command line arguments, which I'd argue is an improvement on your initial approach which may be limited to 9, depending on which shell you're using.
It may be worthwhile to note that this only finds users with home folders directly under /home.
I run systems where some sets of users may have home folders in different locations.
Were that an issue, parsing /etc/passwd for accounts with value UID in the user range, and detecting the home folder field, and testing its validity and existance would be a more rigerous solution.
That may be far beyond the need here, just thought I should mention it.
And that even that method could be 'fooled' by some unexpected non-user accounts in high UID space.
It took me a while to understand what you were trying to accomplish with that for loop, but I think I get it now: You want the loop to iterate though the command line parameters, and then refer to a specific parameter variable, say "$1", inside the loop using a syntax like $${a}, am I right?
The problem is related to the way parameters are expanded. You want "$${a}" to expand to something like "$1" or "$2" initially, with 1 or 2 being the value of $a, and then you want the shell to expand the actual parameter variable ($1 or $2, depending on the value of $a). As you've seen, that's doesn't work.
While some clever coding using delayed expansion might work, may a suggest an alternative approach? How about focusing on $1 and then use shift to iterate through the command line arguments? Just create a loop that runs while $1 is non-null, and inside that loop, check for the existence of a home directory and run shift at the end:
Code:
while ! [ "$1" == "" ]; do
if [ -d /home/$1 ]; then
echo $1 has a home directory
else
echo $1 does not have a home directory
fi
shift
done
(I replaced your "ls dir, pipe to grep, check exit code" test with if [ -d dir ], as that's much less likely to return a false positive.)
This way, you'll be able to handle any number of command line arguments, which I'd argue is an improvement on your initial approach which may be limited to 9, depending on which shell you're using.
Thank you for your reply. The above coding is to get single username as a parameter. If i want to pass muliple username as a parameter, is there any other possible way without using $$a??
Due to the use of $$, the output is showing me PID.
Actual output:
$$a--> {$$}a --->{6712}a ----> 6712a ---> showing PID plus 'a'
Expecting output
$$a---> ${$a} --->${1} ---> $1 ---> 1st parameter value
it would be helpful for me, if you let me know the proper syntax to get above result.
Thank you!!
It may be worthwhile to note that this only finds users with home folders directly under /home.
I run systems where some sets of users may have home folders in different locations.
Were that an issue, parsing /etc/passwd for accounts with value UID in the user range, and detecting the home folder field, and testing its validity and existance would be a more rigerous solution.
That may be far beyond the need here, just thought I should mention it.
And that even that method could be 'fooled' by some unexpected non-user accounts in high UID space.
Yes. it is great idea. I understand that home directory may present in different location too. Grepping home directory from /etc/passwd is a best way.
Thank you for your reply. The above coding is to get single username as a parameter. If i want to pass muliple username as a parameter, is there any other possible way without using $$a??
Did you try the code I posted? It does support multiple user accounts as arguments. In fact, it supports any number of arguments, unlike your approach which may be limited to 9 arguments ($1 - $9).
Quote:
Originally Posted by arunkumar26
Due to the use of $$, the output is showing me PID.
Actual output:
$$a--> {$$}a --->{6712}a ----> 6712a ---> showing PID plus 'a'
Expecting output
$$a---> ${$a} --->${1} ---> $1 ---> 1st parameter value
it would be helpful for me, if you let me know the proper syntax to get above result.
I attempted to explain why this isn't working: You're expecting the shell to perform variable expansion twice, once from "$${a}" to "$1" (or whichever number $a may contain), and then again from "$1" to the contents of the $1 variable. The shell just doesn't expand variables recursively like that.
The first expansion returns a literal $ character (due to the backslash escape) followed by the contents of the variable $a. Then echo $1 is evaluated, returning the contents of $1.
In general, using eval is not a recommended practice since it basically just runs whatever you pass it. If you make a simple mistake or a malicious user is able to manipulate the input to embed a command, you may end up executing said command and compromise the system. Anyway, here's how it might work:
Code:
for (( a=1; a<=$#; a++ )) do
tempvar=\$$a
user_acct=$(eval echo $tempvar)
if [ -d /home/$user_acct ]; then
echo $user_acct has a home directory
else
echo $user_acct does not have a home directory
fi
done
(Thought experiment: Imagine what would happen in the above script if the $1 variable somehow contained the text "foo ; dd if=/dev/zero of=/dev/sda". eval is potentially very dangerous.)
As for locating a user's home directory by searching through /etc/passwd, that may not be such a good idea. It will work on most standalone systems, but will fail if the user account is stored in a database.
A (much) better approach would be to parse the output from getent passwd. It returns user information in exactly the same format as used by the /etc/passwd file, but it fetches that information from whichever source the system is configured to use, be that /etc/passwd, NIS, Active Directory/winbind, an LDAP server, or something else entirely.
Here's a version of my code using getent:
Code:
while ! [ "$1" == "" ]; do
home_dir=$(getent passwd | grep ^$1\: | cut -d : -f 6)
if [ ! "$home_dir" == "" ] && [ -d $home_dir ] ; then
echo $1 has a home directory
else
echo $1 does not have a home directory
fi
shift
done
And here's a (horribly insecure) version that expands variables recursively using eval:
Code:
for (( a=1; a<=$#; a++ )) do
tempvar=\$$a
user_acct=$(eval echo $tempvar)
home_dir=$(getent passwd | grep ^$user_acct\: | cut -d : -f 6)
if [ ! "$home_dir" == "" ] && [ -d $home_dir ]; then
echo $user_acct has a home directory
else
echo $user_acct does not have a home directory
fi
done
Note that since grepping the output from the getent command (or the /etc/passwd file for that matter) will return an empty string if the user either doesn't exist or doesn't have a defined home directory, an extra test is required to check for a blank directory variable. For some reason, if [ -d $var ] evaluates to "true" if $var is blank.
Listen to Ser Olmy, he has excellent taste.
I was wondering about that use of grep though, I think another solution may serve better: using the above solution without eval but in my style.
Code:
while [[ -n "$1" ]]; do
if id ${1} >/dev/null 2>&1
then
home_dir=$(getent passwd $1 | cut -d: -f6)
if [[ -n "$home_dir" ]] && [[ -d $home_dir ]] ; then
echo "${1} has a home directory ${home_dir}"
else
echo "${1} does not have a home directory."
fi
else
echo "${1} is not a user"
fi
shift
done
Since getent with a parameter only outputs for that parameter, the disk access become avoidable.
I added a test for real users simply because I cannot leave well enough alone. Ever. And Ser Olmy may know a better way.
Distribution: Linux From Scratch, Slackware64, Partedmagic
Posts: 3,067
Rep:
To use the value of a bash variable to point to another variable you don't need to use eval you can do sort of 'c' type pointer like so:
Code:
AVAR="some text"
ANOTHERVAR="more text"
POINTERVAR="AVAR"
echo $AVAR
some text
echo $POINTERVAR
AVAR
echo ${!POINTERVAR}
some text
POINTERVAR="ANOTHERVAR"
echo ${!POINTERVAR}
more text
This is read only you can't asign values with "!" but it does avoid at least one use of eval, this is not POSIX complient ( I think ) so if you need to use this with a different shell than BASH you will have to check that it works on that shell.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.