command_not_found_handler not working in mac - linux

so I have this bash code in my .bashrc file...I'm using Mac OS X Yosemite
command_not_found_handle ()
{
runcnf=1;
retval=127;
[ ! -S /var/run/dbus/system_bus_socket ] && runcnf=0;
[ ! -x /usr/libexec/packagekitd ] && runcnf=0;
if [ $runcnf -eq 1 ]; then
/usr/libexec/pk-command-not-found $#;
retval=$?;
else
echo "lalalla";
retval=1;
fi;
return $retval
}
I've used this code before in linux environment and it works just fine...whenever the user enters a bash command that doesn't exist, it would default by echoing "lalalal".....however when I use this on my Mac OS X Yosemite, it doesn't work despite the fact that my .bashrc file is properly registered (I've executed source ~/.bash_profile and my .bash_profile contain the code source ~/.bashrc
other command that exist in my .bashrc are executing just fine....
what did I do wrong and how can I make mac use command_not_found_handle whenever the user enters a command that doesn't exist in mac?
UPDATE
#tristan so I upgraded bash via brew which is confirmed when I run bash --version which outputs
GNU bash, version 4.3.30(1)-release (x86_64-apple-darwin14.0.0)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
moreover I redid source .bash_profile
nonetheless when I enter a command that doesnt exist it still displays
-bash: askldfasf: command not found
what did I do wrong?

command_not_found_handle was introduced to Bash version 4.
OS X Yosemite ships with bash-3.2 by default.
To introduce some facsimile of this, you could check the exit code of every command to look for exit code 127 ("command not found") and append a call to that function after. You could probably patch in this behavior on your own by checking the exit code from the prior command is 127 and calling your custom command_not_found_handle function (using $? and PROMPT_COMMAND).
That said, if I was in your shoes, I'd probably upgrade Bash by installing it via homebrew (brew install bash or from source.
e.g.
bash-4.3$ cat not_found.bash
command_not_found_handle()
{
echo ":("
}
bash-4.3$ source not_found.bash
bash-4.3$ a
:(
I tested your script as it currently stands on my machine as well:
bash-4.3$ source pillar.bash
bash-4.3$ a
lalalla
Test source-ing your script interactively to make sure it's the same on your machine.

Related

How to solve $PATH not resolving in VSCode

After recent upgrade of Fedora 30 -> Fedora 31 I'm observing that when I launch a terminal from within VSCode for the project that I'm working on, I see this message:
bash: sed: command not found
~/data/Programming/JS/React vgorcinschi $
It is complaining about sed because I have a script in ~/.bashrc that tries to include in PS1 information about git branches:
# somewhere in ~/.bashrc
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\] \u $ "
If, within the same terminal, I do man sed it will complain in the same manner about man. If I open a system terminal and navigate to the same location my path would look like this:
~ vgorcinschi $ cd ~/data/Programming/JS/React
~/data/Programming/JS/React (ch14) vgorcinschi $ echo $PATH
./node_modules/.bin:/home/vgorcinschi/.nvm/versions/node/v10.6.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/home/vgorcinschi/.local/bin:/home/vgorcinschi/bin:/home/vgorcinschi/.local/bin:/home/vgorcinschi/bin:/usr/local/java/jdk1.8.0_231/bin:/opt/maven/bin:/snap/bin
NB Note how sed works from within the same directory.
Repeating echo $PATH from VS Code terminal yields just this: /home/vgorcinschi/data/Programming/JS/React/node_modules/.bin
I think this question may come-up so these are the contents of my ~/.config/Code/User/settings.json:
{
"git.enableSmartCommit": true,
"metals.javaHome": "/usr/local/java/jdk1.8.0_231",
"window.zoomLevel": 0,
"terminal.integrated.shell.linux": "/usr/bin/bash",
"editor.tabSize": 2,
"editor.detectIndentation": false,
"terminal.external.linuxExec": "bash"
}
The following could also be very important. The directory above is on a partition which is on HDD (/dev/sdb1) , my ~/.bashrc and ~/.bash-profile are on a SSD (/dev/mapper/fedora-home).
If I open an empty directory with VS Code on the main partition (on SSD) I don't have this issue with the Code's terminal. But I didn't have it on the other partition either before the upgrade - this was just two days ago.
So I am not sure what is the issue really due to, but hopefully someone could help me with it.
Update [2020.10.30]
.node_modules appear on the path inside VSCode terminal because of these lines in ~/.bashrc:
if [ -d "$PWD/node_modules/.bin" ]; then
PATH="$PWD/node_modules/.bin"
fi
VS Code version
Version: 1.50.1
Commit: d2e414d9e4239a252d1ab117bd7067f125afd80a
Date: 2020-10-13T14:44:48.716Z
Electron: 9.2.1
Chrome: 83.0.4103.122
Node.js: 12.14.1
V8: 8.3.110.13-electron.0
OS: Linux x64 5.8.15-101.fc31.x86_64
Well that's embarrassing. As it becomes obvious from my latest description update I was re-setting the PATH once ~/.node_modules were in a sub-directory. So A solution was to add as a suffix the existing PATH in the if block:
if [ -d "$PWD/node_modules/.bin" ]; then
PATH="$PWD/node_modules/.bin:$PATH"
fi
Since I haven't played with ~/.bashrc in a while, I have no idea how did it use to work before.

"set: illegal option -" on one host but not the other

I've written a sh script in one of my ubuntu VMs which works fine, but when I try to run it in my other VMs, it does not work. Both VMs should be the same. With bash --version both VMs reply with:
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
With lsb_release -a, both also reply:
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.3 LTS
Release: 14.04
Codename: trusty
My security_steps.sh script looks like this:
#!/bin/sh
set -e
if ! [ -f svn_up_action.sh ]; then
echo "svn_up_action.sh is missing. Please make sure it is in the same directory as this script."
exit
fi
When I do: sudo sh security_steps.sh, the console errors with:
: not foundeps.sh: 6: security_steps.sh:
security_steps.sh: 7: set: Illegal option -
How can I figure out what's going on with the VM of the non-working shell? I feel like the shells are somehow different. I appreciate your help!
This almost certainly means your file has DOS newlines -- thus, hidden CR characters at the end.
Thus, set -e becomes set -e$'\r' (using bash-specific syntax to represent the CR character), which isn't a valid option.
This also explains the : not found, as a CR will reset the cursor to the beginning of the line, truncating an error message of the form sh: commandname: not found by making the commandname instead an operation that moves the cursor to the beginning of the line.
I had *.sh file throwing me this while running it on Windows (via GitBash).
I've had to change line endings to UNIX/OSX format.
In Windows:
choco install dos2unix
dos2unix file.sh
In Linux:
sudo apt install dos2unix
dos2unix file.sh
dos2unix converts the file to the Unix type.
After doing this, try to run the application again or the file.
If you run into this problem because you are touching your files on a Windows machine, Notepad++ is your friend.
Inspection
View > Show Symbol > Show All Characters
Look for CR LF line endings, rather than LF line endings!
Solving
Search > Replace (Ctrl+H)
Make sure Search Mode is set to Extended
Find \r\n and replace with \n
I got the same Error,
Later I found that these raise because My shell script file moved from a windows machine to Linux machine(there may be a chance of formating or Encoding error).
So I have created the document in Linux machine itself. It solved the issue.
This "May" help few, I am posting this because it worked for me.
You can use the below command, it will remove the hidden CR characters
sed -i 's/\r$//' filename

How can I test my Bash script on older versions of Bash?

I'm working on a Bash library and want to ensure I'm supporting as many environments as possible - including old installations of Bash. My development environment is Bash 4.3, but some of my users may well be running much older versions and presently I have no way to confirm or deny that my library will work for them. In particular I'd like to be compatible with OSX (which still ships with Bash 3.2, AFAIK).
I know Bash can run in POSIX-compliant mode; is there a similar setting to disable modern functionality? Or a way to run Bash in some sort of compatibility mode? I'm looking for any technique short of actually finding and booting up old operating systems and testing my library there.
Update
For example, I've avoided using associative arrays since they were introduced in Bash 4, but it's hard to be sure without testing that I'm not accidentally using some other Bash 4+ feature.
Finally coming back to this question, it's pretty easy to just compile (without installing) the bash version(s) you're interested in. Here's how I'm testing Bash 3.2.57:
$ mkdir ~/bash
$ cd ~/bash
$ wget http://ftp.gnu.org/gnu/bash/bash-3.2.57.tar.gz
$ tar xvzf bash-3.2.57.tar.gz
$ cd bash-3.2.57
$ ./configure
$ make
# if `make` fails due to yacc, run `sudo apt-get install byacc`
# No need to run `make install`
$ ./bash -version
GNU bash, version 3.2.57(1)-release (armv7l-unknown-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
Now you have a bash 3.2.57 binary you can run, without actually "installing" it or modifying your normal environment.
To run a shell script against this version:
$ ./bash your_script.sh
To enter a clean interactive prompt:
$ env -i PATH="$PWD:$PATH" ./bash --noprofile --norc
bash-3.2$ bash -version
GNU bash, version 3.2.57(1)-release (armv7l-unknown-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
bash-3.2$
Using env -i rather than just calling ./bash directly leaves you with a mostly-empty environment (run env from inside the shell to see what's still set). Updating the PATH allows calls to bash (e.g. bash -version) to invoke the local bash shell, not the system-wide installation (but note this pulls in your whole PATH). Adding --noprofile --norc avoids loading your .bashrc and associated scripts.
If you don't want to pick up any PATH modifications, just execute export PATH="$PWD:$PATH" once inside the subshell instead of as part of the env command.
I have a Docker image (repo) using these installation steps, if that's helpful for folks to reference. I wouldn't necessarily suggest using this image directly, but you're welcome to copy from the Dockerfile/install script. MIT licensed.
Although it's nice to know that it's possible to compile arbitrary versions of bash locally (as discussed in my other answer), these days there's a much simpler option - the official Docker bash images.
To test a script against multiple bash versions is often as simple as:
for v in 3 4 5; do # or whatever versions you're interested in
docker run -v "$PWD:/mnt" "bash:$v" \
bash /mnt/your_script.sh
done
Have a look at shenv: https://github.com/shenv/shenv. Just like rbenv, pyenv, goenv and others, but for shells, it lets you install different versions of Bash among others (zsh, fish, yash, etc.).
(Disclaimer: I'm the one who forked pyenv into shenv!)
You can use Bash own facilities to emulate older version of Bash. Look up "compat" options on shopt.
Mind you, while it does change behavior as described under each compatNN entry in the man page, it does not remove features that are otherwise present on the current version. For example, this doesn't cause any errors:
shopt -s compat31
shopt -s globstar
Even though globstar was only introduced on Bash 4.0.

Bash complains "have not a command" when login

I have a file named "upstart" in /etc/bash_completion.d/ with the following content:
# bash-completion for the upstart event-based init replacement
# (http://upstart.ubuntu.com / https://launchpad.net/upstart)
#
# We don't provide completion for 'init' itself for obvious reasons.
have initctl &&
_upstart_jobs()
{
initctl list|awk '{print $1}'|sort -u
} &&
The confusing part is the line have initctl &&, I have configured bash to source
all files in /etc/bash_completion.d/ and every time I login it complains
that command have cannot be found. What is that line for?
Short Answer: maybe you should install bash-completion package.
In general, you don't need to manually source the files in /etc/bash_completion.d/.
It is automatically imported by bash_completion script.
bash_completion script is called by /etc/bash.bashrc (at least for Ubuntu and Arch Linux), which would be called by default.
In Ubuntu, bash_completion script is in bash-completion package and placed in /etc/bash_completion
In Arch Linux, bash_completion script is in bash-completion package and placed in /usr/share/bash-completion/bash_completion
Therefore, installing bash-completion script would help if you are using Ubuntu or Arch Linux.

How to overcome an incompatibility between the ksh on Linux vs. that installed on AIX/Solaris/HPUX?

I am involved in the process of porting a system containing several hundreds of ksh scripts from AIX, Solaris and HPUX to Linux. I have come across the following difference in the way ksh behaves on the two systems:
#!/bin/ksh
flag=false
echo "a\nb" | while read x
do
flag=true
done
echo "flag = ${flag}"
exit 0
On AIX, Solaris and HPUX the output is "flag = true" on Linux the output is "flag = false".
My questions are:
Is there an environment variable that I can set to get Linux's ksh to behave like the
other Os's'? Failing that:
Is there an option on Linux's ksh to get the required behavior? Failing that:
Is there a ksh implementation available for Linux with the desired behavior?
Other notes:
On AIX, Solaris and HPUX ksh is a variant of ksh88.
On Linux, ksh is the public domain ksh (pdksh)
On AIX, Solaris and HPUX dtksh and ksh93 (where I have them installed) are consistent with ksh
The Windows NT systems I have access to: Cygwin and MKS NT, are consistent with Linux.
On AIX, Solaris and Linux, bash is consistent, giving the incorrect (from my perspective) result of "flag = false".
The following table summarizes the systems the problem:
uname -s uname -r which ksh ksh version flag =
======== ======== ========= =========== ======
Linux 2.6.9-55.0.0.0.2.ELsmp /bin/ksh PD KSH v5.2.14 99/07/13.2 false
AIX 3 /bin/ksh Version M-11/16/88f true // AIX 5.3
/bin/ksh93 Version M-12/28/93e true
SunOS 5.8, 5.9 and 5.10 /bin/ksh Version M-11/16/88i true
/usr/dt/bin/dtksh Version M-12/28/93d true
HP-UX B.11.11 and B.11.23 /bin/ksh Version 11/16/88 true
/usr/dt/bin/dtksh Version M-12/28/93d true
CYGWIN_NT-5.1 1.5.25(0.156/4/2) /bin/ksh PD KSH v5.2.14 99/07/13.2 false
Windows_NT 5 .../mksnt/ksh.exe Version 8.7.0 build 1859... false // MKS
Update
After some advice from people in my company we decided to make the following modification to the code. This gives us the same result whether using the "real" ksh's (ksh88, ksh93) or any of the ksh clones (pdksh, MSK ksh). This also works correctly with bash.
#!/bin/ksh
echo "a\nb" > junk
flag=false
while read x
do
flag=true
done < junk
echo "flag = ${flag}"
exit 0
Thanks to jj33 for the previously accepted answer.
Instead of using pdksh on linux, use the "real" ksh from kornshell.org. pdksh is a blind re-implementation of ksh. kornshell.org is the original korn shell dating back 25 years or so (the one written by David Korn). AIX and Solaris use versions of the original ksh, so the kornshell.org version is usually feature- and bug- complete. Having cut my teeth with SunOS/Solaris, installing kornshell.org ksh is usually one of the first things I do on a new Linux box...
After some advice from people in my company we decided to make the following modification to the code. This gives us the same result whether using the "real" ksh's (ksh88, ksh93) or any of the ksh clones (pdksh, MSK ksh). This also works correctly with bash.
#!/bin/ksh
echo "a\nb" > junk
flag=false
while read x
do
flag=true
done < junk
echo "flag = ${flag}"
exit 0
Thanks to jj33 for the previous accepted answer.
I installed 'ksh' and 'pdksh' on my local Ubuntu Hardy system.
ii ksh 93s+20071105-1 The real, AT&T version of the Korn shell
ii pdksh 5.2.14-21ubunt A public domain version of the Korn shell
ksh has the "correct" behavior that you're expecting while pdksh does not. You might check your local Linux distribution's software repository for a "real" ksh, instead of using pdksh. The "Real Unix" OS's are going to install the AT&T version of Korn shell, rather than pdksh, by default, what with them being based off AT&T Unix (System V) :-).
Do you have to stay within ksh?
Even if you use the same ksh you'll still call all kinds of external commands (grep, ps, cat, etc...) part of them will have different parameters and different output from system to system. Either you'll have to take in account those differences or use the GNU version of each one of them to make things the same.
The Perl programming language originally was designed exactly to overcome this problem.
It includes all the features a unix shell programmer would want from he shell program but
it is the same on every Unix system. You might not have the latest version on all those
systems, but if you need to install something, maybe it is better to install perl.
The reason for the differences is whether the inside block is executed in the original shell context or in a subshell. You may be able to control this with the () and {} grouping commands. Using a temporary file, as you do in your update, will work most of the time but will run into problems if the script is run twice rapidly, or if it executes without clearing the file, etc.
#!/bin/ksh
flag=false
echo "a\nb" | { while read x
do
flag=true
done }
echo "flag = ${flag}"
exit 0
That may help with the problem you were getting on the Linux ksh. If you use parentheses instead of braces, you'll get the Linux behavior on the other ksh implementations.
Here is the another solution for echo "\n" issue
Steps:
Find ksh package name
$ rpm -qa --queryformat "%{NAME}-%{VERSION}-%{RELEASE}(%{ARCH})\n" | grep "ksh"
ksh-20100621-19.el6_4.3(x86_64)
uninstall ksh
$ sudo yum remove ksh-20100621-19.el6_4.3.x86_64
down load pdksh-5.2.14-37.el5_8.1.x86_64.rpm (Please check OS for 32-bit or 64-bit and choose correct pkg)
Install pdksh-5.2.14-37.el5_8.1.x86_64.rpm
$ sudo yum -y install /SCRIPT_PATH/pdksh-5.2.14-37.el5_8.1.x86_64.rpm
Output before PDKSH install
$ ora_db_start_stop.sh
\n==============
Usage: START
==============\n\n
./ora_db_start_stop.sh START ALL \n
OR \n
./ora_db_start_stop.sh START ONE_OR_MORE \n
\n==============
Usage: STOP
==============\n\n
./ora_db_start_stop.sh STOP ALL \n
OR \n
./ora_db_start_stop.sh STOP ONE_OR_MORE \n\n
After PDKSH install
==============
Usage: START
./ora_db_start_stop.sh START ALL
OR
./ora_db_start_stop.sh START ONE_OR_MORE
==============
Usage: STOP
./ora_db_start_stop.sh STOP ALL
OR
./ora_db_start_stop.sh STOP ONE_OR_MORE
I don't know of any particular option to force ksh to be compatible with a particular older version. That said, perhaps you could install a very old version of ksh on your linux box, and have it behave in a compatible manner?
It might be easier to install a more modern version of amy shell on the AIX/HP-UX boxes, and just migrate your scripts to use sh. I know there are versions of bash available for all platforms.
Your script gives the correct (true) output when zsh is used with the emulate -L ksh option. If all else fails you may wish to try using zsh on Linux.

Resources