How to get $HOME directory of user in bash script root mode? - linux

file name test.sh
echo $HOME
running in root privilege -> sudo test.sh
expected
/home/username/
but getting
/root

sudo runs the script as the root-user
To get the name of the user who initiated sudo you can call echo $SUDO_USER
To get its home directory:
getent passwd $SUDO_USER | cut -d: -f6

Surely the best way is simply:
echo ~username
For assignment, tilde must not be quoted:
username_home=~username
but may be combined with quoted strings, e.g.:
new_path=~username/"${another_variable}"
new_paths_array=(~username/"${yet_another}"/*)
There may be some subtle things to do with $HOME and ~, especially in relation to sudo.
Refer to the POSIX standard regarding tilde expansion. For bash, also see bash tilde expansion.

Related

Get file count at remote location during FTP in shell script on linux server

Requirement : Need to get file count based on wildcard entry present on remote location(Linux server) and store it in variable for validation purpose
Tried the below code
export ExpectedFileCount=$(ftp -inv $FTPSERVER >> $FTPLOGFILE <<END_SCRIPT
user $FTP_USER $FTP_PASSWORD
passive
cd $PATH
ls -ltr ${WILDCARD}*xml| wc -l | sed 's/ *//g'
quit
END_SCRIPT)
But the code is storing the code snippet in the variable and and executing the commands every time I call the variable.
Please suggest the changes in the script to execute the script once and store the value in the variable
This seems to work (on Ubuntu, no promises about portability):
export ExpectedFileCount=`ftp -in $FTPSERVER << END_SCRIPT | tee -a $FTPLOGFILE | egrep -c '\.xml$'
user $FTP_USER $FTP_PASSWORD
passive
cd $REMOTE_PATH
ls -l
quit
END_SCRIPT`
Issues:
$REMOTE_PATH used in place of $PATH for remote directory (as $PATH has a special meaning)
only a simple ls -l is performed inside the ftp session, and the output parsed locally, as it does not support arbitrary shell commands
I can't see how to capture the output of a command with a heredoc using $(...), but it seems to work with backticks if the closing backtick is after the final delimiter

How to run .profile inside a script

I have to SU first and run a profile inside a script, when I ran below script..the profile is giving log to the terminal and the parameters resolved in profiel or not resolving for the next line.thanks in advance
if [ $owner = "user1" ]
then
su -c " . ~/.profile; cd $LOG_DOR; cat $job.log" - user1
else
echo "$owner not found"
fi
To read in a file to the current shell, use source
source ~/.profile
When the shell parses a double-quoted string, it does variable expansion on the contents (replacing $varname with the variable's value) before executing the command. In this case, since the LOG_DOR and job variables are defined in ~/.profile (and not in the script) and that means that
su -c " . ~/.profile; cd $LOG_DOR; cat $job.log" - user1
will be expanded to:
su -c " . ~/.profile; cd ; cat .log" - user1
Which isn't what you want at all. To defer expansion of the variables, you can use single-quotes instead of double:
su -c ' . ~/.profile; cd $LOG_DOR; cat $job.log' - user1
But I'll actually recommend a couple of other changes as well: Put double-quotes around the variable references, to avoid possible problems when they do get expanded, and join the commands with && (instead of ;) so that if one fails it skips the rest (rather than blindly trying to continue):
su -c '. ~/.profile && cd "$LOG_DOR" && cat "$job.log"' - user1
EDIT: apparently in this case job is defined in the script, and LOG_DOR in ~/.profile; therefore the expansion of $job should be done immediately, and $JOB_DOR deferred. Fortunately, it's possible to use double-quotes and escape (\) the $ for expansions you want deferred. You'll also need to escape some other special characters, like included double-quotes (which would end the string if not escaped). Here, I've also switched to single-quotes around the $job reference, in case it contains any special characters that'd otherwise cause trouble (although this will fail if it contains any single-quotes itself):
su -c ". ~/.profile && cd \"\$LOG_DOR\" && cat '$job.log'" - user1

'Permission Denied' even while running as root

I have a simple bash shell script:
user_exists=cat /etc/passwd | grep 'GNU Mailman'
echo $user_exists
when I run this script with sudo ./'script_name', I get a permission denied error on the line where I attempt to access /etc/passwd. What am I doing wrong here?
To understand why, you have to look at the line the way that bash looks at the line:
user_exists=cat /etc/passwd | grep 'GNU Mailman'
According to bash, you are (temporarily) setting the environment variable user_exists to have the value cat. With that value set, then the program /etc/passwd is executed and its output sent to grep 'GNU Mailman'. Since /etc/passwd does not have execute permission, this command fails for lack of permission.
The solution is to use the proper format for process substitution as outlined by Vladimir Kolesnikov:
user_exist=$(grep 'GNU Mailman' /etc/passwd)
user_exists=$(cat /etc/passwd | grep 'GNU Mailman')
or better yet,
getent passwd username

Why does the output differ when executed from a shell script?

According to this post, I run this from the command line:
USER_HOME=$(getent passwd $SUDO_USER | cut -d: -f6)
and get the following output:
/root
/usr/sbin
/bin
/dev
/bin
/usr/games
/var/cache/man
/var/spool/lpd
/var/mail
/var/spool/news
/var/spool/uucp
/bin
/var/www
/var/backups
/var/list
/var/run/ircd
/var/lib/gnats
/nonexistent
/var/lib/libuuid
/home/user
/var/run/vboxadd
/var/lib/puppet
/var/run/sshd
When I run this in a script (as sudo, which is the point of the whole thing --- as sudo, ~ expands to /root):
USER_HOME=$(getent passwd $SUDO_USER | cut -d: -f6)
echo $USER_HOME
I get my correct path /home/user.
Why can I not invoke my function manually to get the same output?
Because when not using sudo, $SUDO_USER is not set and you get the output of getent passwd without further argument, which lists all users. The cut then extracts the home directory part.
Replace $SUDO_USER with $USER when not running with sudo.
Note that using getent passwd ${SUDO_USER:-$USER} should work in both cases.

bash - how to pipe result from the which command to cd

How could I pipe the result from a which command to cd?
This is what I am trying to do:
which oracle | cd
cd < which oracle
But none of them works.
Is there a way to achieve this (rather than copy/paste of course)?
Edit : on second thought, this command would fail, because the destination file is NOT a folder/directory.
So I am thinking and working out a better way to get rid of the trailing "/oracle" part now (sed or awk, or even Perl) :)
Edit :
Okay that's what I've got in the end:
cd `which oracle | sed 's/\/oracle//g'`
You use pipe in cases where the command expects parameters from the standard input. ( More on this ).
With cd command that is not the case. The directory is the command argument. In such case, you can use command substitution. Use backticks or $(...) to evaluate the command, store it into variable..
path=`which oracle`
echo $path # just for debug
cd $path
although it can be done in a much simpler way:
cd `which oracle`
or if your path has special characters
cd "`which oracle`"
or
cd $(which oracle)
which is equivalent to backtick notation, but is recommended (backticks can be confused with apostrophes)
.. but it looks like you want:
cd $(dirname $(which oracle))
(which shows you that you can use nesting easily)
$(...) (as well as backticks) work also in double-quoted strings, which helps when the result may eventually contain spaces..
cd "$(dirname "$(which oracle)")"
(Note that both outputs require a set of double quotes.)
With dirname to get the directory:
cd $(which oracle | xargs dirname)
EDIT: beware of paths containing spaces, see #anishpatel comment below
cd `which oracle`
Note those are backticks (generally the key to the left of 1 on a US keyboard)
OK, here a solution that uses correct quoting:
cd "$(dirname "$(which oracle)")"
Avoid backticks, they are less readable, and always quote process substitutions.
You don't need a pipe, you can do what you want using Bash parameter expansion!
Further tip: use "type -P" instead of the external "which" command if you are using Bash.
# test
touch /ls
chmod +x /ls
cmd='ls'
PATH=/:$PATH
if cmdpath="$(type -P "$cmd")" && cmdpath="${cmdpath%/*}" ; then
cd "${cmdpath:-/}" || { echo "Could not cd to: ${cmdpath:-/}"; exit 1; }
else
echo "No such program in PATH search directories: ${cmd}"
exit 1
fi
besides good answer above, one thing needs to mention is that cd is a shell builtin, which run in the same process other than new process like ls which is a command.
https://unix.stackexchange.com/questions/50022/why-cant-i-redirect-a-path-name-output-from-one-command-to-cd
http://en.wikipedia.org/wiki/Shell_builtin
In response to your edited question, you can strip off the name of the command using dirname:
cd $(dirname `which oracle`)

Resources