OS X 10.10 - path_helper causing invalid characters in path? - macos

In an earlier question, I had problems with invalid/non-ASCII characters in my path statement. Thanks to some helpful answers, I was able to fix most of the problem, but I still need some help.
To resolve the problem, I made changes to my /private/etc/profile file and removed these lines:
if [ -x /usr/libexec/path_helper ]; then
eval `/usr/libexec/path_helper -s`
fi
if [ "${BASH-no}" != "no" ]; then
[ -r /etc/bashrc ] && . /etc/bashrc
fi
Once I removed those lines, the corrupted characters in my path went away. So, I suspect that path_helper was picking up some invalid characters and inserting them in my Path. But, I'm very new to all of this, so I'm not sure how to go about investigating how path_helper modifies my path?

path_helper is returning a line of shell code that is being executed with eval.
So if you want to see what it is doing just run it (either by hand or in your profile script) without the eval and backticks.

Try checking the files in /etc/paths.d if they contain any invalid (maybe invisible) character. For me it helped to do a "wc *" in that directory. That lists in the first column the number of lines in each file. I had some files without trailing newline. After adding a newline to the end of each file it worked. I had to call
PATH=''
eval `/usr/libexec/path_helper -s`
To make the change effective.
I could not find a pattern how to force a specific invalid pattern into the path, but the number of errors and the position of errors did not directly relate to the order of my files or the number of files with missing newline.

Related

Why is executing a ruby command on bash to command file not working?

Code from .command file:
cd "$(dirname "$0")"
g1=Hi-Lo
echo Welcome to Ruby_Games! So far, you can play $g1.
echo What game would you like to play?
read game_choice
if [$game_choice == $g1]
then
ruby Hi-Lo.rb
fi
Output:
Welcome to Ruby_Games! So far, you can play Hi-Lo.
What game would you like to play?
Hi-Lo
/Users/Abbas/Desktop/Ruby_Games/LAUNCHER.command: line 6: [Hi-Lo: command not found
logout
So what exactly is going wrong? Thanks
I believe you need double quotes in your if statement
Similar to example 6.4 here: http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-6.html
cd "$(dirname "$0")"
g1=Hi-Lo
echo Welcome to Ruby_Games! So far, you can play $g1.
echo What game would you like to play?
read game_choice
if [ "$game_choice" = "$g1" ]
then
ruby Hi-Lo.rb
fi
You need spaces between each element of the test (aka [) command. That is, you need a space between [ and $game_choice, between $game_choice and =, etc. Also, as #GregHNZ pointed out, you should use double-quotes around variable references, in case they contain spaces or certain other shell metacharacters. Finally, == in a test expression is a bash extension; use = instead, and it'll work in more basic shells as well. Result:
if [ "$game_choice" = "$g1" ]
Spaces are important delimiters in shell syntax; there are places they're required and places they're forbidden, and very very few places where they're optional. In many languages, you can add or remove spaces to make the code more readable, but that's not the case in shell.
BTW, I recommend using shellcheck.net; it does a pretty good job of spotting errors like this. Actually, it points out a couple I didn't think of: you should add a shebang line to the beginning of the script, and using cd without checking for an error risks the rest of the script running in an unexpected directory. So you should use something like this:
#!/bin/bash
cd "$(dirname "$0")" || {
echo "Error cd'ing to the script's directory" >&2
exit 1
}

bash variable filename with underscore unrecognized?

I am writing a script that will symlink all of my dotfiles related to bash into the home directory. I want the script to check if the filenames already exists, so that I I can rename/move them.
For some reason can't get my if test-command to recognize filenames that have an underscore in them.
When testing for files that already exist, this script:
#!/bin/bash
for name in bashrc bash_profile bash_aliases
do
filename=$HOME"/."$name
if [ -e "$filename" ]; then
echo "${filename} exists"
else
echo "${filename} doesn't exist"
fi
done
Outputs:
/home/xavier/.bashrc exists
/home/xavier/.bash_profile doesn't exist
/home/xavier/.bash_aliases doesn't exist
What is it about the underscore that is causing this behavior, and how do I fix it?
The code is correct as posted and underscore is not a problematic character in general.
You mention that you're symlinking the files -- if you're sure the files are there, verify that they are not broken symlinks. -e file will be false if the final target of the link doesn't exist.
Other things that can cause this are:
lacking permissions
invisible unicode characters like a zero-width space
similar-looking unicode characters like bаsh_profile which has a fullwidth low line instead of an underscore.
running the script in a chroot or sandbox
checking that the file exists in a different terminal than the one used for running the script -- it could be chrooted, SSH'd to another machine or started before a directory was mounted over the dir, and therefore have a different view of the fs

Path variables become longer and longer after doing source ~/.bashrc

This might be a stupid question, but I wonder how to avoid this problem.
In my ~/.bashrc file, I add some local paths. The following is an example of the PYTHONPATH. In my work environment, I need to do "source ~/.bashrc" from time to time, and the following PYTHONPATH becomes longer and longer which is quite annoying.
Instead of appending to the existing PYTHONPATH, it might be nicer if I can append it to the "clean" PYTHONPATH. Is there anyway of doing this?
export PYTHONPATH=$PYTHONPATH:$CLIENTS:$EXPERIMENTAL/my_pythonlib:/mnt/src/cloud/chanwcom/chanwcom-speech/mnt/experimental/users/chanwcom/bin:$CK_MEDIA_FRAMEWORK
EDIT: I answered the question about keeping a clean PATH.
#mklement0 commented correctly, that the OP is talking about the PYTHONPATH.
I could correct my answer, but perhaps other readers have the same problem for PATH.
Dear Chanwcom, you can use the methods beneath, you only need to rename the variables.
Add some tests before expanding your path. Choose one of these examples.
if [[ -z "${my_clean_path}" ]]; then
my_clean_path="${PATH}"
fi
# some more commands
PATH="${my_clean_path}:${PYTHONPATH}"
or
if [[ -z "${python_added}" ]]; then
PATH="${PATH}:${PYTHONPATH}" # PATH += also possible here
fi
or (my favorite, without additional variables)
if [[ "${PATH}" != *${PYTHONPATH}* ]]; then
PATH="${PATH}:${PYTHONPATH}" # PATH += also possible here
fi
or open a second shell before changing the path. exit to the first shell and open a new fresh shell.
The "right" way to solve this is as chepner mentioned in a comment -- modify your PYTHONPATH in .bash_profile which gets run at login, rather than in .bashrc which gets run for every shell.
If you're unable to adjust the scripts or tools that append repeated items to your path, you may be able to clean things up by removing non-unique values.
Here's a strategy I use, which involves converting my $PATH to an array, inverting the array (i.e. turning array values into subscripts of an associative array) and then rebuilding the path from the array index:
if [[ ${BASH_VERSINFO[0]} -ge 4 ]]; then
path_a=( ${PATH//:/ } )
declare -A path_b=()
for i in ${path_a[#]}; do path_b[$i]=1; done
IFS=: eval 'PATH="${!path_b[*]}"'
fi
export PATH
You can adjust this for PYTHONPATH easily enough.
Note that associative arrays were introduced with Bash version 4, so they may not be available with the default bash in OSX. You should be fine just about anywhere else that's modern, though.
Note also that this solution will break if any of the directories in the path contain colons. But your path would be broken in that case anyway, I think.
Also, note that this solution uses eval, which some people consider dangerous, unclean, smelly. In the right setting, though, it can be a fine cheese.

What is [[: not found error?

I tried to execute a file containing a shell script.
I get an error called "[[: not found" error at the last line. How to resolve it?
[[ is bash. sh wants the [ variant.
Either change that to /usr/bin/bash (or wherever bash is located on your system), or adjust the expression accordingly:
if [ status_of_job -eq 0 ];
[ is actually an executable in linux. but [[ is not.
Try
if [ status_of_job -eq 0 ]; then
(note the single [] set).
This interpreter:
#!/usr/bin/sh
Is either not bash or your file doesn't have the shebang in the right place.
ls -l /usr/bin/sh will tell you if it's a symlink to something other than bash.
If it is bash, then check that there's no leading characters before the #!.
You may find you stumble at other blocks later with POSIX shell related issues. People don't really understand how much bash actually provides until it's taken away. Take a look at this so you can hopefully avoid any other issues:
http://pubs.opengroup.org/onlinepubs/7908799/xcu/shellix.html

Deleting a directory contents using shell scripts

I am a newbie to Shell scripting. I want to delete all the contents of a directory which is in HOME directory of the user and deleting some files which are matching with my conditions. After googled for some time, i have created the following script.
#!/bin/bash
#!/sbin/fuser
PATH="$HOME/di"
echo "$PATH";
if [ -d $PATH ]
then
rm -r $PATH/*
fuser -kavf $PATH/.n*
rm -rf $PATH/.store
echo 'File deleted successfully :)'
fi
If I run the script, i am getting error as follows,
/users/dinesh/di
dinesh: line 11: rm: command not found
dinesh: line 12: fuser: command not found
dinesh: line 13: rm: command not found
File deleted successfully :)
Can anybody help me with this?
Thanks in advance.
You are modifying PATH variable, which is used by the OS defines the path to find the utilities (so that you can invoke it without having to type the full path to the binary). The system cannot find rm and fuser in the folders currently specified by PATH (since you overwritten it with the directory to be deleted), so it prints the error.
tl;dr DO NOT use PATH as your own variable name.
PATH is a special variable that controls where the system looks for command executables (like rm, fuser, etc). When you set it to /users/dinesh/di, it then looks there for all subsequent commands, and (of course) can't find them. Solution: use a different variable name. Actually, I'd recommend using lowercase variables in shell scripts -- there are a number of uppercase reserved variable names, and if you try to use any of them you're going to have trouble. Sticking to lowercase is an easy way to avoid this.
BTW, in general it's best to enclose variables in double-quotes whenever you use them, to avoid trouble with some parsing the shell does after replacing them. For example, use [ -d "$path" ] instead of [ -d $path ]. $path/* is a bit more complicated, since the * won't work inside quotes. Solution: rm -r "$path"/*.
Random other notes: the #!/sbin/fuser line isn't doing anything. Only the first line of the script can act as a shebang. Also, don't bother putting ; at the end of lines in shell scripts.
#!/bin/bash
path="$HOME/di"
echo "$path"
if [ -d "$path" ]
then
rm -r "$path"/*
fuser -kavf "$path"/.n*
rm -rf "$path/.store"
echo 'File deleted successfully :)'
fi
This line:
PATH="$HOME/di"
removes all the standard directories from your PATH (so commands such as rm that are normally found in /bin or /usr/bin are 'missing'). You should write:
PATH="$HOME/di:$PATH"
This keeps what was already in $PATH, but puts $HOME/di ahead of that. It means that if you have a custom command in that directory, it will be invoked instead of the standard one in /usr/bin or wherever.
If your intention is to remove the directory $HOME/di, then you should not be using $PATH as your variable. You could use $path; variable names are case sensitive. Or you could use $dir or any of a myriad other names. You do need to be aware of the key environment variables and avoid clobbering or misusing them. Of the key environment variables, $PATH is one of the most key ($HOME is another; actually, after those two, most of the rest are relatively less important). Conventionally, upper case names are reserved for environment variables; use lower case names for local variables in a script.

Resources