Bash: rewriting emacs command in bash_profile - emacs

I'm trying to write a command in my bash_profile to replace the default emacs command that will emacs a file if it exists, and if it doesn't exist, will copy a template to the new file and then emacs that.
What I attempted was:
function emacs()
{
if [ ! -f ${1} ]; then \
cp /FILEPATH/template.sh ${1}; fi;
builtin emacs ${1}
}
but the error I'm getting is "-bash: builtin: emacs: not a shell builtin"
How do I create a new function to replace the emacs command and then call the original emacs command within that function if emacs is not a builtin command?

You want command emacs, not builtin emacs. See help command.
As an aside, doesn't emacs have some sort of internal support for new-file templates? You might want to take a look at this: http://www.emacswiki.org/emacs/TemplatesMode. (Disclaimer: I don't use emacs; this was just one of the first pages I found while searching for "emacs new file template.)

(edit: sorry, command emacs in the other answer is better, use that.)
builtin only works for actual shell builtins like test, read, ...
Use the explicit path to emacs instead:
function emacs()
{
if [ ! -f ${1} ]; then \
cp /FILEPATH/template.sh ${1}; fi;
/usr/bin/emacs ${1}
}

Related

How can I edit crontabs in VS Code?

If I try to use Visual Studio Code (on macOS 10.15) to edit my crontab, it opens an empty file without the contents of my crontab.
$ VISUAL='code' crontab -e
crontab: no changes made to crontab
I didn't actually expect this to work (without -w) but include it for completeness. But when I add the -w it still fails.
$ VISUAL="code -w" crontab -e
crontab: code -w: No such file or directory
crontab: "code -w" exited with status 1
It occurred to me that there may be some weirdness with quoting, but neither single quotes nor the following fixed anything:
$ function codew() {
function> code -w "$1"
function> }
$ export VISUAL='codew'
$ crontab -e
The problem seems to be that the crontab's tempfile is not actually present. But how do I solve this? How can I use VS Code to edit crontabs?
Create a file touch ~/code-wait.sh:
#!/bin/bash
OPTS=""
if [[ "$1" == /tmp/* ]]; then
OPTS="-w"
fi
/usr/local/bin/code ${OPTS:-} -a "$#"
Make this file executable:
chmod 755 ~/code-wait.sh
Add to your .bashrc or .bash_profile or .zshrc:
export VISUAL=~/code-wait.sh
export EDITOR=~/code-wait.sh
Run command:
EDITOR='code' crontab -e
here the setting works for me.
.bashrc
## vscode
export VISUAL=/path/to/code-wait.sh
export EDITOR=/path/to/code-wait.sh
code-wait.sh
#!/bin/sh
code -w $*
That is quite a complex issue because there is no way to detect which tool calls the preferred editor. The TTY is the same and no environment variables can help.
Still, I was able to come up with a solution that enables the foreground mode (wait) for temporary files. IMHO, most if not all tools that use external editors and are waiting for them to save the file do use temporary files.
Full script is at https://github.com/ssbarnea/harem/blob/master/bin/edit but I will include here the main snippet:
#!/bin/bash
OPTS=""
if [[ "$1" == /tmp/* ]]; then
OPTS="-w"
fi
/usr/local/bin/code ${OPTS:-} -a "$#"

How can I get zsh to inherit the complete autocompletion?

I have an little shell script (named "run") which redirects all output of a program to /dev/null:
#!/bin/bash
$# &> /dev/null &
disown +
How can I say zsh that the whole autocompletion shall work for this?
I mean
$ run git com<TAB>
autocomplete to
$ run git commit
I was able to make that work by adding:
compdef _command run
to my .zshrc file.
I've based my answer on this bash question. It was worth giving it a try with compdef - surprisingly it worked.
As I'm still zsh/autocompletion newbie I cannot explain the inner workings and you should probably go through the documentation or other sources to find more on the topic.

Why Parameter Expansion is not working? [duplicate]

#!/bin/bash
jobname="job_201312161447_0003"
jobname_pre=${jobname:0:16}
jobname_post=${jobname:17}
This bash script gives me Bad substitution error on ubuntu. Any help will be highly appreciated.
The default shell (/bin/sh) under Ubuntu points to dash, not bash.
me#pc:~$ readlink -f $(which sh)
/bin/dash
So if you chmod +x your_script_file.sh and then run it with ./your_script_file.sh, or if you run it with bash your_script_file.sh, it should work fine.
Running it with sh your_script_file.sh will not work because the hashbang line will be ignored and the script will be interpreted by dash, which does not support that string substitution syntax.
I had the same problem. Make sure your script didnt have
#!/bin/sh
at the top of your script. Instead, you should add
#!/bin/bash
For others that arrive here, this exact message will also appear when using the env variable syntax for commands, for example ${which sh} instead of the correct $(which sh)
Your script syntax is valid bash and good.
Possible causes for the failure:
Your bash is not really bash but ksh or some other shell which doesn't understand bash's parameter substitution. Because your script looks fine and works with bash.
Do ls -l /bin/bash and check it's really bash and not sym-linked to some other shell.
If you do have bash on your system, then you may be executing your script the wrong way like: ksh script.sh or sh script.sh (and your default shell is not bash). Since you have proper shebang, if you have bash ./script.sh or bash ./script.sh should be fine.
Try running the script explicitly using bash command rather than just executing it as executable.
Also, make sure you don't have an empty string for the first line of your script.
i.e. make sure #!/bin/bash is the very first line of your script.
Not relevant to your example, but you can also get the Bad substitution error in Bash for any substitution syntax that Bash does not recognize. This could be:
Stray whitespace. E.g. bash -c '${x }'
A typo. E.g. bash -c '${x;-}'
A feature that was added in a later Bash version. E.g. bash -c '${x#Q}' before Bash 4.4.
If you have multiple substitutions in the same expression, Bash may not be very helpful in pinpointing the problematic expression. E.g.:
$ bash -c '"${x } multiline string
$y"'
bash: line 1: ${x } multiline string
$y: bad substitution
Both - bash or dash - work, but the syntax needs to be:
FILENAME=/my/complex/path/name.ext
NEWNAME=${FILENAME%ext}new
I was adding a dollar sign twice in an expression with curly braces in bash:
cp -r $PROJECT_NAME ${$PROJECT_NAME}2
instead of
cp -r $PROJECT_NAME ${PROJECT_NAME}2
I have found that this issue is either caused by the marked answer or you have a line or space before the bash declaration
Looks like "+x" causes problems:
root#raspi1:~# cat > /tmp/btest
#!/bin/bash
jobname="job_201312161447_0003"
jobname_pre=${jobname:0:16}
jobname_post=${jobname:17}
root#raspi1:~# chmod +x /tmp/btest
root#raspi1:~# /tmp/btest
root#raspi1:~# sh -x /tmp/btest
+ jobname=job_201312161447_0003
/tmp/btest: 4: /tmp/btest: Bad substitution
in my case (under ubuntu 18.04), I have mixed $( ${} ) that works fine:
BACKUPED_NB=$(ls ${HOST_BACKUP_DIR}*${CONTAINER_NAME}.backup.sql.gz | wc --lines)
full example here.
I used #!bin/bash as well tried all approaches like no line before or after #!bin/bash.
Then also tried using +x but still didn't work.
Finally i tried running the script ./script.sh it worked fine.
#!/bin/bash
jobname="job_201312161447_0003"
jobname_post=${jobname:17}
root#ip-10-2-250-36:/home/bitnami/python-module/workflow_scripts# sh jaru.sh
jaru.sh: 3: jaru.sh: Bad substitution
root#ip-10-2-250-36:/home/bitnami/python-module/workflow_scripts# ./jaru.sh
root#ip-10-2-250-36:/home/bitnami/python-module/workflow_scripts#

same aliases and functions for user and root in fish shell

How can I make aliases defined in ~/.config/fish/config.fish and functions defined in ~/.config/fish/functions available for the root user as well?
symlinking to /root/.config/fish didn't do the job. Furthermore, I'd also like to be able to use my functions and aliases via sudo, which is currently not working as well.
How do you guys do that?
I don't have a solution for the first problem (I don't have any functions that are useful for the root user), but the second one (functions not working as an argument for sudo) can be solved with a wrapper function:
function sudo
if functions -q $argv[1]
set argv fish -c "$argv"
end
command sudo $argv
end
The issue is of course that sudo is an external command (usually at /usr/bin/sudo) that cannot know about fish internals like function definitions. So this wrapper will call fish if you give it a function name. Of course, since this launches a new fish session, some things, like cd will not be useful because it won't alter the state of the main fish session.
I use a symlink to my config.fish and works perfectly. Have you checked the permissions?
777 lrwxrwxrwx 1 root root 35 Dez 21 2015 /root/.config/fish/config.fish -> /home/lara/.config/fish/config.fish
In newer versions you can also use the directory /etc/fish/ for system-wide configuration
The problem with sudo I solved with an alias:
# -E just preserv env. It's not really
# necessary, but may be useful.
function sudo; command sudo -sE $argv; end
from sudo man page:
-s, --shell
Run the shell specified by the SHELL environment variable if it is set or the shell specified by the invoking user's
password database entry. If a command is specified, it is passed to
the shell for execution via
the shell's -c option. If no command is specified, an interactive shell is executed.
Old question that I came across while attempting to do the same thing myself.
Neither existing solution from #faho or #LaraMaia solves the first part of the question, which is really what I needed for my use-case. Both solutions only handled functions that are defined in ~/.config/fish/functions. In-memory functions and aliases that have not been "saved" do not work.
So here's a version that does work for aliases/in-memory functions:
function sudo
if functions -q -- "$argv[1]"
set cmdline (
for arg in $argv
printf "\"%s\" " $arg
end
)
set -x function_src (string join "\n" (string escape --style=var (functions "$argv[1]")))
set argv fish -c 'string unescape --style=var (string split "\n" $function_src) | source; '$cmdline
command sudo -E $argv
else
command sudo $argv
end
end
Commented and slightly expanded version at this Gist.

lgrep and rgrep in Emacs

I am having problems with the greps in Emacs.
a) grep doesnt seem to understand the .[ch] for searching .c and .h files. This is a default option provided by Emacs with the lgrep command. The example is searching for the word "global" in .c/.h files.
grep -i -nH "global" *.[ch]
grep: *.[ch]: No such file or directory
Grep exited abnormally with code 2 at Mon Feb 16 19:34:36
Is this format not valid?
b) Using rgrep I get the following error:
find . "(" -path "*/CVS" -o -path "*/.svn" -o -path "*/{arch}" -o -path "*/.hg" -o -path "*/_darcs" -o -path "*/.git" -o -path "*/.bzr" ")" -prune -o -type f "(" -iname "*.[ch]" ")" -print0 | xargs -0 -e grep -i -nH "global"
FIND: Wrong parameter format
Grep finished (matches found) at Mon Feb 16 19:37:10
I am using Emacs 22.3.1 on Windows XP with the GNU W32 Utils (grep, find, xargs etc.). Grep v2.5.3 and find v4.2.20.
What am I missing?
UPDATE:
Too bad one can't accept multiple answers...since the solution to my problems are spread out.
grep -i -nH "global" *.c *.h
This solves the first problem. Thanks luapyad!
(setq find-program "c:\\path\\to\\gnuw32\\find.exe")
emacs was indeed using the Windows find.exe. Forcing the gnu32 find fixed the second problem. Thanks scottfrazer.
However, I still like ack best.
I found out that using:
(setq find-program "\"C:/path/to/GnuWin32/bin/find.exe\"")
(setq grep-program "\"C:/path/to/GnuWin32/bin/grep.exe\"")
Works better in windows, since you could have a space laying around the path and will screw up eventually.
Notice I used the two programs in my .emacs file.
Hope it's of some help to some other programmer in need ;)
Well, there is always Ack and Ack.el
For a) it looks like there are simply no .c or .h files in the current directory.
For b) Windows is trying to use its own find instead of the one from the GNU W32 Utils. Try:
(setq find-program "c:\\path\\to\\gnuw32\\find.exe")
Adam Rosenfield comment is worth expanding into an answer:
grep -r --include=\*.[ch] --exclude=\*{CVS,.svn,arch} -i -nH
To make the example given in this question work, use this:
grep -i -nH --include=\*.[ch] "global" *
It is also helpful to set the variable grep-command providing defaults to M-x grep:
(setq grep-command "grep -i -nH --include=\*.[ch] ")
Also here are some other useful command line parameters to grep:
-n print the line number
-s suppress error messages
-r recursive
I think the general problem is the windows cmd "shell" behaves very differently to a unix shell in respect to filename expansion regexps and wildcards.
To answer your (a) above try using:
grep -i -nH "global" *.c *.h
(You will still get an "invalid argument" if no *.c's or *.h's exist).
Or you can use command line option --include=\*.[ch] to make windows grep do "proper" filename pattern matching (see grep --help for other options)
I usually just use M-x grep and alter the command line args when prompted if I need to. But I just tried running M-x lgrep and got the same thing as you. It simply means that no files match *.[ch] in the current directory. You can customize the default options to include -r and search recursively through child directories as well:
M-x customize-group RET grep RET
Search for lgrep in that buffer to find/edit the Grep Template.
As far as M-x rgrep goes, I suspect it has something to do with the Windows version of find not liking the default options. That command works fine for me on Linux. Search for rgrep in that same customize buffer and tweak those options until the Windows find is happy.
Sorry I can't be more help with the Windows options, but I'm not familiar with them.