symlinks in bash script aren't working - macos

I'm writing a bash script on Mac OS X that makes a symlink but when I try and open the symlink that I created it doesn't go anywhere and I get an error that it can't find the original.
OriginalPath="~/PathTo/bundle1.bundle"
NewPath="/OtherPath/bundle1.bundle"
sudo ln -s $OriginalPath $NewPath
I've also tried this:
sudo ln -s ${OriginalPath} ${NewPath}

ln sets the redirect to exactly what you give it, so it'll be interpreted relative to the location of the link. I'm actually not 100% sure how links will handle a ~, but I don't believe bash will expand it within quotes, and since it is a bash expansion, not a general filesystem one, I suspect the redirect will point to an actual directory named ~, which probably doesn't exist. Either figure out the relative path or expand it into an absolute path.

Assuming ${OriginalPath} already exists (and if it doesn't, hey, that's your problem):
The first thing I'd look at is to see if the tilde expansion is the problem. Change OriginalPath to the full path name (e.g., /Users/jpc/PathTo/bundle1.bundle). If that fixes the problem, then either just go with that or find out how to turn on tilde expansion in the shell or use the environment variable ${HOME} instead of tilde expansion.
Probably best not to use tilde expansion in the shell script anyway, as you might not be able to make sure that all users running the script will have it turned on.

Related

Replace $PATH with string/file? Set $PATH to null and append?

Backup, first.
Before attempting to resolve this, people are worried about $PATH changes breaking things. Backup your path with echo $PATH > $HOME/bak/conf/path.bak and remember (don't put any raw files into the bak dir). Confirm your backup with cat $HOME/bak/conf/path.bak.
A minimal $PATH!
My desired path is /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin.
This is a minimalist path that should break nothing on most default Linux installs (Backup, first).
I have a huge $PATH that is completely useless (like 120 lines of $PATH--caused by WSL [more later]). So far, I only know how to add to path and remove single directories from $PATH via seg.
Sounds like it should pop right up on search engines. I have a headache in my eye--:
how do I set $PATH to a raw string or purge it so I can append from null?.
Bonus points for anyone who can tell me how to set $PATH from the contents of a file!?
Best guess:
import sys, sys.path.insert(0, '/your/path')--!NO This did not work!
Temporary workaround:
You can move the path to a neutral file (or use whatever means you know) and replace / with / and then use sed to cut the unwanted part out:
PATH=$(echo "$PATH" | sed -e 's/:\/tons:\/of:\/unwanted:\/garbage$//')
Make sure you put everything you don't want between s/ and $//').
Where is this long $PATH coming from?
Related question: How to remove the Win10's PATH from WSL --$PATH is inherited every time you re-launch or perform some other actions such as possibly changing users or environments.
Why is this question different:
As if there isn't enough typing, S.O. has a nuisance dialog that asks me to write and explain why purging $PATH is different from removing one directory/path from $PATH.
Because a punch in the face isn't a kick in the butt.
If I'm understanding your question, you simply want to know how to set your Bash PATH to a fixed string (or erase it completely) and have it persist across restarts of the shell?
If so, then I'll start off by saying that this isn't recommended as it will break other things. If not now, then later.
But if you really want to set the PATH to a fixed value every time Bash starts ...
Short answer first:
Assuming fairly "default" startup files (where ~/.profile sources ~/.bashrc):
Edit your ~/.profile (or ~/.bash_profile in the rare case it exists) and add:
# Remove entirely
unset PATH
export -n PATH
# Optionally
export PATH=/new/pathItem1:/new/path/Item2
Adding this to the bottom of the file should override any other PATH modifications done previously. However, future application installations can make modifications below that, therefore overriding it.
In a very rare case where you have an interactive Bash session that isn't startup by a login shell, you could also make the same modifications to ~/.bashrc.
(Not necessarily required if the modification is the last thing called during startup, but) make sure that there are no other PATH adjustments in your ~/.bashrc or ~/.bash_profile.
More explanation:
Where is this long $PATH coming from?
Your path in Bash in WSL can potentially come from a few sources:
WSL's init process sets a default PATH for the starting application (shell). This is currently (in WSL 0.70.8):
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib
Since this is done before your ~/.profile runs, there's no need to worry about disabling it.
As you've pointed out, WSL automatically appends the Windows path to the Linux path so that you can launch Windows executables. This can be disabled using the method in the question you linked, but it's not necessary if you simply want to override the entire PATH. Setting the PATH in your ~/.profile comes after WSL sets it for the initial process (your shell).
Bash itself has a built-in, default path that is hardcoded into it for "fallback" in case no other path is passed in. This rarely ever takes effect. Most Linux systems are going to set the PATH through some other mechanism, meaning the fallback never gets activated. A typical Linux system will set the default PATH via /etc/environment, but this isn't used under WSL since the init mechanism mentioned above is needed instead.
If using Systemd or another init system in WSL, then Bash (and other POSIX shells) will process /etc/profile and files in /etc/profile.d when starting. These files may contain PATH modifications. Again, since these come before your ~/.profile, (re)setting the PATH to a fixed value will override any of these settings.
Finally, your ~/.profile or ~/.bash_profile (for login shells) and ~/.bashrc (for interactive shells are read. Typically, PATH modifications in these files look something like:
export PATH="/new/path/item:$PATH"
This prepends to the path, making that new item take priority over the previous items.
However, leaving out the existing :$PATH part will simply set it to a string literal.
It should be obvious, but if you do this without including the "normal" OS paths, you will be unable to call any command that isn't built in to Bash already with specifying its fully qualified path. For instance, ls will fail. Note that you can still:
$ ls
ls: command not found
$ /usr/bin/ls
# works
Also note that ~/.profile is called for login shells. It is possible, however, to tell WSL to launch Bash without reading ~/.profile:
wsl ~ -e bash --noprofile
The resulting shell will still have the default WSL path in this case.

How to export a windows path and then cd to is using the variable?

I typically export variables with directories/paths that I frequently visit so that I don't have to type the whole thing (or tab). For example, in Windows, I'll create an environment variable and then use it in a bash prompt (git bash): cd $MY_LONG_PATH
Or, I can export a path in my .bashrc and use it the same way. Both ways work fine until you add spaces into the mix. For example, I'd like to be able to export a path like C:\Users\name\OneDrive - Company, Inc\Documents\My Project Folder\. You might say, just use a different directory. Unfortunately, I can't change this one because it's controled by my org. So, considering I can't change it, how can I get it to work with an environment or exported variable? I've tried both ways, but can't seem to get it right. I've escaped all the chars in .bashrc c\:/Users/name/OneDrive\ -\ Company,\ Inc/Documents/My\ Project\ Folder. This will work on the bash cli when I type it in (terminal), but doesn't work when I export it as a variable. I've tried using quotes around the whole thing and that doesn't work either. I've tried it in the regular windows environment variable control panel, and that doesn't work. Does anyone know the fix, if there is one?
Again, the goal is just to be able to: cd $LONG_PATH with the variable containing a windows directory with spaces
My test on Gitbash
# remove the trailing backslash
MY_LONG_PATH="C:\Users\name\OneDrive - Company, Inc\Documents\My Project Folder" <---
# use quotes
$ ls -l "$MY_LONG_PATH"
total 0
drwxr-xr-x 1 user 197613 0 Apr 14 00:10 test/
$ cd "$MY_LONG_PATH"
$ pwd
/c/Users/name/OneDrive - Company, Inc/Documents/My Project Folder
$ ls
test/
I figured out a way to do this. While ufopilot's answer was good, I didn't like having to use quotes for variables that have special characters. Also, I found that when you use tab-completion, there's a bug in bash (bash-completion) that will escape the $ in a variable on the command-line, which in turn would break the directory path. So to fix all of this, I first created a soft symlink to the path that contains spaces using Windows cmd:
> mklink /D C:\Users\name\projects "C:\Users\name\OneDrive - Company, Inc\Documents\My Project Folder"
And now I can export the variable in .bashrc:
export LONG_PATH="C:\Users\name\projects"
This allows me to change directories without putting quotes around LONG_PATH:
> cd $LONG_PATH
To fix the problem with tab-completion, I had to run the bash command:
shopt -s direxpand
What this does is it expands the variable first and then escapes the special characters if needed (for example, if yet another directory has spaces). Everything works like my other path variables now!

bash: "which adb" returns nothing, but "command -v adb" returns what i'd expect

This is a bash weirdness that's been bugging me.
I'm on OSX.
I've installed the android SDK, and as a result the adb tool is located in a folder in my home directory. That folder appears in my path as reported by env as ~/Development/android_sdk_latest/platform-tools.
adb itself runs just fine, but when I do which adb the result is empty. If I do command -v adb, the result is the full path, as expected: /Users/me/Development/android_sdk_latest/platform-tools/adb
adb does not appear in my aliases.
What subtlety of bash paths or which am I in the dark on?
You've run into a subtle incompatibility between /bin/bash and the which command.
On my system (Linux Mint), the which command is actually a shell script, not a built-in command, and its first line is #! /bin/sh. That means that it uses /bin/sh's handling of the $PATH variable.
This can vary depending on how /bin/sh is set up (it's sometimes a symlink to /bin/bash), but a little experimentation shows that bash handles a literal ~ character in $PATH as if it were the full path to your home directory, but /bin/sh does not. Since you have
~/Development/android_sdk_latest/platform-tools
as one of the elements of your $PATH, bash (your interactive shell) can find the adb command, but sh (the shell used by which) cannot.
On some systems, apparently including your OSX system, which is a binary executable. Again, since it's not a bash script, it's not going to match bash's treatment of $PATH.
I recommend making two changes.
First, don't put a literal ~ in your $PATH. For example, to append the platform-tools directory to your $PATH, rather than this:
export PATH="$PATH:~/Development/android_sdk_latest/platform-tools" # BAD!
do this:
export PATH="$PATH:$HOME/Development/android_sdk_latest/platform-tools"
The $HOME will expand to the path to your home directory (when you run the export command, not when you use $PATH later). ~ is not expanded within double-quoted strings.
Second, rather than using the which command, use the type command that's built into bash. type will follow the rules of your current shell rather than those of /bin/sh, and it will be able to report shell functions and aliases that which is unable to see. It has several useful command-line options; type help type at a bash prompt for details.
The bash shell's treatement of ~ characters in $PATH is documented in the bash manual's section on Tilde Expansion.

Command not found although in PATH

In my sh or tcsh I can call netstat without problems. With Bash however, I get the message:
bash: netstat: command not found
The PATH variable is exactly the same for all shells:
PATH=/usr/lpp/Printsrv/bin:/usr/lpp/java/J6.0/bin:/EXEX/exec:/bin:/usr/sbin:/etc:/usr/lpp/perl/bin:.:/usr/lpp/ported/bin:.:.
Netstat is in the /bin directory and so should be included in the PATH...
Any ideas?
Thanks!
We don't quite have enough information yet to state what's gone wrong here, but I'm going to go out on a limb and suggest your path isn't what you think it is, not to mention the path you quote is very non-standard and most likely not what you want.
What you say your path is...
The path you quote looks like this when broken down:
/usr/lpp/Printsrv/bin
/usr/lpp/java/J6.0/bin
/EXEX/exec
/bin
/usr/sbin
/etc
/usr/lpp/perl/bin
.
/usr/lpp/ported/bin
.
.
The current working directory (.) three times over won't cause a problem, but it does look a little odd.
You're missing the standard directory /usr/bin. And if you have /usr/sbin you ought to have /sbin in there as well for consistency.
I can't imagine why you would ever put /etc in your path. There should never be executables in that directory.
What your path actually is...
There should be no difference between the shells. It's highly unlikely that you've found a bug in the shells here so lets assume your path isn't quite the same in each and try to figure out why it looks like it does...
All shells should tell you that your path is the same thing with BOTH of the two commands:
# The PATH variable
echo "$PATH"
# The PATH environment variable
env | /bin/grep PATH
Remember there are two kinds of variable. Internal Variables and Environment Variables. PATH should be an environment variable.
I'm not sure how you found the following line:
PATH=/usr/lpp/Printsrv/bin:/usr/lpp/java/J6.0/bin:/EXEX/exec:/bin:/usr/sbin:/etc:/usr/lpp/perl/bin:.:/usr/lpp/ported/bin:.:.
If this was taken from your .profile or .bashrc then it should be exported to ensure the PATH gets set as an environment variable.
export PATH=/usr/lpp/Printsrv/bin:/usr/lpp/java/J6.0/bin:/EXEX/exec:/bin:/usr/sbin:/etc:/usr/lpp/perl/bin:.:/usr/lpp/ported/bin:.:.

Fullpath in OS X

I am a few steps before starting my first real programming project and I am preparing my machine. I noticed that my fullpath (what I get when I "echo $PATH" in the terminal) does not look like a "normal" one (as I see "usr/bin" quite a lot of times). What does it mean? How does it affect my use of the terminal? And how, if, can I change it back to the default one?
EDIT: I can change it just by typing "PATH=the_name_of_the_path" but it's not permanent, if I quit the session I am running and start terminal again, what I get is "/Applications/lejos_nxj/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin" (and that's because I changed it some months ago so I could usel lejos_nxj, for a course at university). Is it better I change it back to the "normal" again or should I stop worrying about it? How can I change it anyway, in case I had to?
$PATH is a variable specifying a set of directories where executable programs are located. It's normal to see /usr/bin there.
Basically, if you type a command on the terminal, like cat for example, it's going to look for cat in those directories. This way, you don't have to specify the full path to all your frequently used commands.
Here is an example of a "normal" path on a new OS X 10.6 install:
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/git/bin:/usr/X11/bin
If you see the same entries repeated again and again, then you probably have a mixup with your .bashrc vs. .bash_profile. You should set the PATH in the .bash_profile, not .bashrc, to avoid this.
$PATH under all *nixes is actually a list of colon-separated directories. Unless you see several times the /usr/bin entry, nothing's wrong (and even if you see it several times, it doesn't mean it's broken either).
At any rate, you should post what you get.
My path looks like this:
frak:~ seth$ echo $PATH
/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin
Yours should look pretty much the same. Each directory is separated by ':'. However, even if you do have /usr/bin more than once, it won't make any difference.
Observe:
frak:~ seth$ whereis units
/usr/bin/units
frak:~ seth$ units attoparsecs/s m/s
* 0.030856776
/ 32.407793
Add a /usr/bin again:
frak:~ seth$ PATH=$PATH:/usr/bin
frak:~ seth$ echo $PATH
/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/bin
And everything still works fine:
frak:~ seth$ whereis units
/usr/bin/units
frak:~ seth$ units attoparsecs/s m/s
* 0.030856776
/ 32.407793
PATH is a shell variable specifying where to find executables. For example, if you do a ftp (file transfer), the shell will look for the command ftp in those directories in your PATH variable before executing it. There's nothing wrong with that. If /usr/bin is not specified in your PATH, then everytime you need to use ftp, you need to give full path name , eg /usr/bin/ftp
Note that for a normal user, /usr/sbin should not be in PATH because those in /usr/sbin are mostly administrative commands.

Resources