ZSH completion from script prompt (like BASH's read -e) - bash

In a bash shell script you can prompt the user for input and enable readline completion for the user with the -e flag. (e.g. read -e -p 'GET YOUR FILE: ' file would allow a the user to use tab-completion to find the file.)
ZSH's completion is more advanced and extendable, so I hoped that I might be able to find a zsh builtin that allowed similar behavior.

I'm sure there's a better answer (I just recently started experimenting with zsh), but you can use vared.
$ vared -c line

Related

commenting not working in iTerm2 on macOS Big Sur

I'm using iTerm2(Z shell) on macOS 11.5.2. Because I use certain Perl one-liners (one line of Perl command in a shell application like iTerm2) a lot, it would be a lot easier if adding some comments to the one-liners so I could navigate back to it using the search function of iTerm2.
Normally, it's like perl path-to-perl-snippet/xxx.pl --an-arg xxx --other-args xxx a.txt #this is doing some task to do some work with a.txt.
Recently, I clean install the system and find some issues with commenting using #, i.e. the content behind # is interpreted by the command. This is not what I intend; It should be just comments.
At first, I thought it was a Perl problem. But the simplest command ls #display list also has the exact same problem, giving the following error ls: #display: No such file or directory ls: list: No such file or directory"
The expected behavior should be like executing ls (without the #display list) in the iTerm2, which is to display all the files under current directory.
So the real problem probably doesn't lie with Perl. It could be a setting problem with iTerm2 or other settings.
Any suggestions would be helpful. Thank you.
Newer versions of OS X (as of 10.15 Catalina) use the zsh shell by default, which has an "interactivecomments" shell option. It is set "off" by default. Turn it on with:
setopt interactivecomments
To preserve this setting for future shells, edit that line into your ~/.zshrc file.
The setting is documented in the man zshoptions section or online at https://zsh.sourceforge.io/Doc/Release/Options.html#index-comments_002c-in-interactive-shells. It is listed there as INTERACTIVE_COMMENTS, but the introduction to that section says:
These names are case insensitive and underscores are ignored. For example, ‘allexport’ is equivalent to ‘A__lleXP_ort’.
This means that you have several ways to enable the option (a partial list):
set -o interactivecomments
set -o Interactive_Comments
set -k
setopt interactivecomments
as well as disabling it (a partial list):
set +o interactivecomments
set +o Interactive_Comments
set +k
setopt nointeractivecomments
Whether or not # introduces a comment in an interactive shell is controlled by the interactive_comments option. It should be enabled by default, but if it has been disabled, run
shopt -s interactive_comments

Call bash function using vim external command

I use vim's :! external command function all the time, usually providing % as an argument to the shell command. For example :
:!psql -f %
I also have a lot of bash shell functions in my .bashrc that I use. For example:
psql-h1 ()
{
/usr/bin/psql -hh1 -d mydb "$#"
}
These bash functions aren't available from :! inside of vim. Is there a way to make them available?
Export your functions. That is:
psql-h1() { /usr/bin/psql -hh1 -d mydb "$#"; }
export -f psql-h1 ### <-- THIS RIGHT HERE
This will make them available to any copy of bash run as a child process, even if it's a noninteractive shell and so doesn't read .bashrc.
An alternative to exporting your functions (which may no reach Vim is there's a non-Bash shell in between; see here for such a case), you can instruct Vim to start an interactive shell, so that your .bashrc is read. Just pass the -i flag to Bash, via Vim's :help 'shellcmdflag'.
:set shcf=-ic
This answer assumes your vim isn't actually using bash to invoke the remote commands - this can be tested by running :!echo $0 in vim.
Specifically for vim, add:
set shell=/bin/bash
to your .vimrc.
In general, there's two strategies I've found to sometimes work when trying to get other programs to invoke my preferred shell:
export SHELL=/bin/bash
in eg. the .profile file, or:
ln -fsn /bin/bash /bin/sh
which updates the sh symlink to point to bash instead.
On many systems (certainly Ubuntu), /bin/sh is a symlink to a sh-compatible shell (such as bash), rather than the sh shell itself. Given this fact, some programs (I've seen this behaviour in GHC) seem to invoke /bin/sh, so changing where it points to will cause the programs to use bash instead.
The accepted answer didn't work for me. I'm going to go with setting shcf, as suggested elsewhere:
:set shcf=-ic
but another solutions is
!source ~/.bashrc && psql ...
Unfortunately, no solution allows the auto-completion for the command I'm creating to work properly. (The auto_completions suggested are for names of files in my current directory, rather than the ones I specified as follows in .bashrc
complete -F _generate_foo_completions foo

bash: vim mode instead of vi mode?

I noticed when in vi mode in bash (i.e. the mode enabled with "set -o vi"), that some commands, such as "diw", that work in vim but not in vi, don't work on the bash command line. Is there an easy way to configure bash so that its keybindings will support vim commands? I would like to be able to enter vim commands on the command line without having to actually start the vim program, as described in this question.
The best way of doing this that I know of would be to use athame.
It can be a surprisingly powerful experience in some cases. I particularly like it for interacting with a repl.
Athame patches your shell to add full Vim support by routing your keystrokes through an actual Vim process. Athame can currently be used to patch readline (used by bash, gdb, python, etc) and/or zsh (which doesn't use readline).
Alternatively I find spacemacs with the eshell to be a reasonably functional if strange solution.
Teach vi-command-mode diw to any software that uses readline (such as bash) by adding this to your ~/.inputrc:
set keymap vi-command
"diw": "bde"
First, the "vi mode" you get with set -o vi is not vi itself. It's an incomplete approximation of vi's behavior built into readline, the command-line editing library used by bash under the hood.
Second, because it is incomplete there's no reason whatsoever to expect every vi command to work.
Third, no, there's no "vim mode" so even less reason to expect any vim commands to work.
Fourth, if you absolutely want to edit the current command-line with Vim-like commands, why don't you go all the way and… actually use Vim:
<C-x><C-e>
That said, $ man readline tells you everything you need to customize its behavior and add bindings.
You can use ble.sh. Which is a command line editor written in pure Bash which replaces the default GNU Readline. I like to call it "zsh for bash".
Appart from vim-style navigation it gives you:
Enhanced completion
Syntax highlighting
Other interesting features
After installation don't forget to add (recommended) to your .bashrc:
# at the start of your .bashrc file
[[ $- == *i* ]] && source /usr/share/blesh/ble.sh --noattach
...
#for vim-style mode
set -o vi
...
#at the end of your .bashrc file
[[ ${BLE_VERSION-} ]] && ble-attach
or you can just:
# at the start of your .bashrc file
source /usr/share/blesh/ble.sh
but this may not work as expected - read this.

PS1='$PWD $ ' doesnt work from shell script

I am not a Solaris expert and I am trying to create a shell script that will change my prompt to PWD and the ksh to bash and I have this:
PS1='$PWD $ ' exec bash --noprofile --rcfile /dev/null
or
PS1='\w $' exec bash --noprofile --rcfile /dev/null
Both of them dont work from a sh. if i add them from the command line then the first time my bash appears on prompt and the second time the PS1='$PWD $' kicks in and my prompt changes.
Firstly, why is PS1='$PWD $' not working from shell script . and why do i have to run the command from command line twice to acheive my results.
Also, in my export/home/syed/ directory there are three files local.login, local.profile, and local.cshrc. is there any way i can use them that when ever i log in i dont need to run my shell script and upon login i get bash shell and my prompt as i want it
(am i asking too much, i dont like the ksh as it does not have any features like up arrow recall last commands and tab auto complete features)
thanks
Syed...
When you exec from within a script, the script is what is replaced, not the parent shell.
Try sourcing the script rather than running it.
Also, in Solaris, you can use passwd -e to change your login shell.
You may be able to symlink ~/.profile to your existing ~/local.profile (or similar). Note that .cshrc is for the C Shell and is not compatible with ksh or Bash.
If you want that your default shell will be bash, change it in /etc/passwd
When you exec bash it sets up its own environment from scratch. Pass it an --rcfile containing the settings you would like for it to inherit.

How do I tell what type my shell is

How can I tell what type my shell is? ie, whether it's traditional sh, bash, ksh, csh, zsh etc.
Note that checking $SHELL or $0 won't work because $SHELL isn't set by all shells, so if you start in one shell and then start a different one you may still have the old $SHELL.
$0 only tells you where the shell binary is, but doesn't tell you whether /bin/sh is a real Bourne shell or bash.
I presume that the answer will be "try some features and see what breaks", so if anyone can point me at a script that does that, that'd be great.
This is what I use in my .profile:
# .profile is sourced at login by sh and ksh. The zsh sources .zshrc and
# bash sources .bashrc. To get the same behaviour from zsh and bash as well
# I suggest "cd; ln -s .profile .zshrc; ln -s .profile .bashrc".
# Determine what (Bourne compatible) shell we are running under. Put the result
# in $PROFILE_SHELL (not $SHELL) so further code can depend on the shell type.
if test -n "$ZSH_VERSION"; then
PROFILE_SHELL=zsh
elif test -n "$BASH_VERSION"; then
PROFILE_SHELL=bash
elif test -n "$KSH_VERSION"; then
PROFILE_SHELL=ksh
elif test -n "$FCEDIT"; then
PROFILE_SHELL=ksh
elif test -n "$PS3"; then
PROFILE_SHELL=unknown
else
PROFILE_SHELL=sh
fi
It does not make fine distinctions between ksh88, ksh95, pdksh or mksh etc., but in more than ten years it has proven to work for me as designed on all the systems I were at home on (BSD, SunOS, Solaris, Linux, Unicos, HP-UX, AIX, IRIX, MicroStation, Cygwin.)
I don't see the need to check for csh in .profile, as csh sources other files at startup.
Any script you write does not need to check for csh vs Bourne-heritage because you explicitly name the interpreter in the shebang line.
Try to locate the shell path using the current shell PID:
ps -p $$
It should work at least with sh, bash and ksh.
If the reason you're asking is to try to write portable shell code, then spotting the shell type, and switching based on it, is an unreliable strategy. There's just too much variation possible.
Depending on what you're doing here, you might want to look at the relevant part of the autoconf documentation. That includes an interesting (and in some respects quite dismal) zoology of different shell aberrations.
For the goal of portable code, this section should be very helpful. If you do need to spot shell variants, then there might be some code buried in autoconf (or at least in one of the ./configure scripts it generates) which will help with the sniffing.
You can use something like this:
shell=`cat /proc/$$/cmdline`
Oh, I had this problem. :D
There is a quick hack, use ps -p $$ command to list the process with PID of the current running process -- which is your SHELL. This returns a string table structure, if you want, you can AWK, or SED the shell out...
The system shell is the thing you see when you open up a fresh terminal window which is not set to something other than bash (assuming this is your default SHELL).
echo $SHELL
Generally, you can find out all the constants defined by running
set
If the output is a lot of stuff then run
set | less
so you can scroll it from the top of the command line or
set > set.txt
To save the output to a file.
Invoking a different interactive shell to bash in your terminal does not mean that your system shell gets changed to something else i.e. your system shell is set to bash although you invoke a csh shell from a bash shell just that one session.
The above means that typing /bin/csh or /bin/python in bash or whatever does not set the system shell to the shell you invoked, at all.
If you really want to see the SHELL constant change then you need to set it to something else. If successful you should see the new shell whenever you open a fresh terminal...
It's old thread but...
In GNU environment You can sh --help and get something like
BusyBox v1.23.2 (2015-04-24 15:46:01 GMT) multi-call binary.
Usage: sh [-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]
Unix shell interpreter
So, the first line is shell type =)

Resources