run zsh script in specified folder - zsh

How to run zsh script in specified folder? How to specify a folder to run a script:
zsh script_name.sh
Documents said that: "-s Force shell to read commands from the standard input. If the -s flag is not present and an argument is given, the first argument is taken to be the pathname of a script to execute." but it does not work.
What is the difference between zsh -c ~/path1/ script1.sh (2 parameters) and zsh -c ~/path1/script1.sh?

You should just open a subshell, Execute the following from zsh or bash (including the parentheses):
(cd ~/path1 && source script1.sh)
Note: If your script is written for zsh, name it script1.zsh instead, since zsh syntax is not retro-compatible with old sh's.

This should work:
zsh -c "cd ~/path1 && ./script_name.sh"

Related

default to zsh interpreter in Mac Terminal?

How can I make sure .sh files are executed with the zshell interpreter from the Mac terminal without specifying the zsh prefix every time? The shell default is set to zshell already but a command to run a .sh file won't execute unless I prefix with zsh...
To change the shell to zsh: chsh -s $(which zsh) (zsh is probably the default shell already).
To run a .sh script without having to use zsh command:
prefix the script with a shebang line such as #!/usr/bin/env zsh.
make the script executable: chmod +x <filename>
run it as ./<filename>

Using uglifyjs on M1 Pro with ZSH throws error

If I execute the following in terminal on my Macbook M1 Pro 2021 with ZSH
uglifyjs js/script.js --compress --mangle --output js/script.min.js -m reserved=['$','require','exports']
I get this error
zsh: no matches found: reserved=[$,require,exports]
But If I switch to bash then it's fine, can anyone help on this to get it fixed on ZSH?
Add quotes:
uglifyjs js/script.js --compress --mangle --output js/script.min.js \
-m "reserved=['$','require','exports']"
In both bash and zsh, square brackets are used for file globbing. The shell is attempting to find files that match the pattern reserved=[<one of these characters>]
In zsh, if there are no matches, you get an error. In bash if there are no matches, the shell silently includes the original pattern.
Which means in bash, you also want to use quotes to prevent file globbing. Otherwise, something like this can happen:
bash> echo reserved=['$','require','exports']
reserved=[$,require,exports]
bash> touch 'reserved=r'
bash> echo reserved=['$','require','exports']
reserved=r

Zsh inherit xtrace option

Similar to this question: bash recursive xtrace, but for Zsh.
How can I make all the Zsh subshells inherit the xtrace option?
For example, if script1.sh is calling ./script2.sh and I run zsh -x script1.sh, I want script2.sh to also have the xtrace mode enabled.
For Bash, the answer is to export the SHELLOPTS variable.
Is there a solution for Zsh?
You can take advantage of startup/shutdown files in Zsh (see man zshall): Zsh will always read (and execute) the file $ZDOTDIR/.zshenv at startup (if ZDOTDIR is unset, HOME is used instead). So you can put set -x in $ZDOTDIR/.zshenv and every Zsh script will run with xtrace mode enabled.
This is how I used it in a script:
env_dir="$(mktemp -d)"
echo "set -x" > "${env_dir}/.zshenv"
export ZDOTDIR="${env_dir}"
zsh "$#"
unset ZDOTDIR
rm -rf "${env_dir}"
In fact, this solution can be used for Bash as well, using the BASH_ENV variable, which points to a file that will, similarly, be executed when Bash starts.

How to always have the same current directory in VIm and in Terminal?

I would like to my terminal current directory follows my VIM one.
Example:
In TERMINAL:
> pwd
=> /Users/rege
> vim
Then in VIM
:cd /Users/rege/project
<Ctrl-z>(for suspend)
In terminal
> pwd
=> /Users/rege/project
I`m using MacOS, zsh, tmux.
I need this because when Im trying to use tags in VIM, tags are check in project from my terminal directory not vim one.
So I need to change terminal current directory always when I change VIM current directory.
What kind of command do you issue in your shell after you suspend Vim? Isn't Vim's :!command enough?
With set autochdir, Vim's current directory follows you as you jump from file to file. With this setting, a simple :!ctags -R . will always create a tags file in the directory of the current file.
Another useful setting is set tags=./tags,tags;$HOME which tells Vim to look for a tags file in the directory of the current file, then in the "current directory" and up and up until it reaches your ~/. You might modify the endpoint to suit your needs. This allows you to use a tags at the root of your project while editing any file belonging to the project.
So, basically, you can go a long way without leaving Vim at all.
If you really need to go back to the shell to issue your commands, :shell (or :sh) launchs a new shell with Vim's current directory. When you are done, you only have to $ exit to go back to Vim:
$ pwd
/home/romainl
$ vim
:cd Projects
:sh
$ pwd
/home/romainl/Projects
$ exit
In bash or zsh and on Unix you can do this: current working directory of the process is represented in /proc/{PID}/cwd as a symlink to a real directory. Speaking about zsh the following code will do the job:
function precmd()
{
emulate -L zsh
(( $#jobstates == 1 )) || return
local -i PID=${${${(s.:.)${(v)jobstates[1]}}[3]}%\=*}
cd $(readlink /proc/$PID/cwd)
}
. Note: with this code you won’t be able to pernamently switch directories in terminal anymore, only in vim or for duration of one command (using cd other-dir && some command).
Note 2: I have no idea how to express this in bash. The straightforward way is to get PIDs of all children of the shell (using ps --ppid $$ -o CMD), filter out the ps process (it will be shown as a child as well), check that there is only one other child and use its PID like in the last line above. But I am pretty sure there is a better way using some shell builtins like I did with zsh’s $jobstates associative array. I also don’t remember what is the analogue of precmd in bash.
Another idea would be making vim save its current directory into some file when you do <C-z> and make shell read this in precmd:
" In .vimrc:
function s:CtrlZ()
call writefile([fnamemodify('.', ':p')], $CWDFILE, 'b')
return "\<C-z>"
endfunction
nnoremap <expr> <C-z> <SID>CtrlZ()
# In .zshrc
function vim()
{
local -x CWDFILE=~/.workdirs/$$
test -d $CWDFILE:h || mkdir $CWDFILE:h
vim $#
}
function precmd()
{
local CWDFILE=~/.workdirs/$$
test -e $CWDFILE && cd "$(cat $CWDFILE)"
}
. It should be easier to port above code to bash.
you can open a new terminal like this
:!xterm -e bash -c "cd %:p:h;bash" &
actually I write this in my .vimrc
nmap <F3> :!xterm -e bash -c "cd %:p:h;bash" &<CR> | :redraw!
For bash users coming by:
Vim: Save pwd at <c-z> (with map and getpwd()).
Bash: Before prompt command, goto directory indicated by vim with PROMPT_COMMAND.
.bashrc
PROMPT_COMMAND='read -r line 2>/dev/null </tmp/cd_vim'\
'&& > /tmp/cd_vim && cd ${line##\r};'$PROMPT_COMMAND
vimrc
function! s:CtrlZ() call writefile([getcwd(),''], '/tmp/cd_vim', 'b')
return "\<C-z>"
endfunction
nnoremap <expr> <C-z> <SID>CtrlZ()
This is ZyX answer edited for bash https://stackoverflow.com/a/12241861/2544873

Whats the difference between running a shell script as ./script.sh and sh script.sh

I have a script that looks like this
#!/bin/bash
function something() {
echo "hello world!!"
}
something | tee logfile
I have set the execute permission on this file and when I try running the file like this
$./script.sh
it runs perfectly fine, but when I run it on the command line like this
$sh script.sh
It throws up an error. Why does this happen and what are the ways in which I can fix this.
Running it as ./script.sh will make the kernel read the first line (the shebang), and then invoke bash to interpret the script. Running it as sh script.sh uses whatever shell your system defaults sh to (on Ubuntu this is Dash, which is sh-compatible, but doesn't support some of the extra features of Bash).
You can fix it by invoking it as bash script.sh, or if it's your machine you can change /bin/sh to be bash and not whatever it is currently (usually just by symlinking it - rm /bin/sh && ln -s /bin/bash /bin/sh). Or you can just use ./script.sh instead if that's already working ;)
If your shell is indeed dash and you want to modify the script to be compatible, https://wiki.ubuntu.com/DashAsBinSh has a helpful guide to the differences. In your sample it looks like you'd just have to remove the function keyword.
if your script is at your present working directory and you issue ./script.sh, the kernel will read the shebang (first line) and execute the shell interpreter that is defined. you can also call your script.sh by specifying the path of the interpreter eg
/bin/bash myscript.sh
/bin/sh myscript.sh
/bin/ksh myscript.sh etc
By the way, you can also put your shebang like this (if you don't want to specify full path)
#!/usr/bin/env sh
sh script.sh forces the script to be executed within the sh - shell.
while simply starting it from command line uses the shell-environemnt you're in.
Please post the error message for further answers.
Random though on what the error may be:
path specified in first line /bin/bash is wrong -- maybe bash is not installed?

Resources