Can I use the .SHELLFLAGS variable to choose "bashrc" file in GNU-Make? - gnu-make

Is it possible to tell the SHELL, e.g. bash, to use a specific (bash)rc file using .SHELLFLAGS?
Below you will see two examples. The first shows what I want to do, and the second illustrates one way of achieving the desired result.
The reason for me asking is that I have a bashrc file (from OpenFOAM) defining a bunch of variables and functions that I want to use in various recipes.
Thank you for your time.
example (not working)
file: bashrc:
export HELLOWORLD="Hello World"
file: Makefile:
SHELL=/bin/bash
.SHELLFLAGS=--rcfile bashrc --
test:
#\
echo "$${HELLOWORLD}"
example (working)
file: bashrc:
export HELLOWORLD="Hello World"
file: Makefile:
.ONESHELL:
SHELL=/bin/bash
test: ; source bashrc
#\
echo "$${HELLOWORLD}"

If you read the bash man page related to the --rcfile option you'll find:
--rcfile file
Execute commands from file instead of the system wide initial‐
ization file /etc/bash.bashrc and the standard personal initial‐
ization file ~/.bashrc if the shell is interactive (see INVOCA‐
TION below).
Note particularly that the shell must be interactive for this to have any effect, but a shell that make invokes is of course not interactive.
Second, if you read the GNU make manual on .SHELLFLAGS you'll see that the default value is -c (or -ec in POSIX mode); the -c option allows the shell to read the script to run from the command line, which is how make invokes the shell. This means when you replace .SHELLFLAGS with your own value, you have to include that.
So with your makefile when make runs the shell it will use this command line:
/bin/bash --rcfile bashrc -- 'echo "${HELLOWORLD}"'
which is clearly not going to work. You need to set .SHELLFLAGS like this:
.SHELLFLAGS = --rcfile bashrc -ic --
The -i option forces an interactive shell, and you need the -c option to tell make to run the first non-option argument as a command.

Related

Zsh completions with multiple repeated options

I am attempting to bend zsh, my shell of choice, to my will, and am completely at a loss on the syntax and operation of completions.
My use case is this: I wish to have completions for 'ansible-playbook' under the '-e' option support three variations:
Normal file completion: ansible-playbook -e vars/file_name.yml
Prepended file completion: ansible-playbook -e #vars/file_name.yml
Arbitrary strings: ansible-playbook -e key=value
I started out with https://github.com/zsh-users/zsh-completions/blob/master/src/_ansible-playbook which worked decently, but required modifications to support the prefixed file pathing. To achieve this I altered the following lines (the -e line):
...
"(-D --diff)"{-D,--diff}"[when changing (small files and templates, show the diff in those. Works great with --check)]"\
"(-e --extra-vars)"{-e,--extra-vars}"[EXTRA_VARS set additional variables as key=value or YAML/JSON]:extra vars:(EXTRA_VARS)"\
'--flush-cache[clear the fact cache]'\
to this:
...
"(-D --diff)"{-D,--diff}"[when changing (small files and templates, show the diff in those. Works great with --check)]"\
"(-e --extra-vars)"{-e,--extra-vars}"[EXTRA_VARS set additional variables as key=value or YAML/JSON]:extra vars:__at_files"\
'--flush-cache[clear the fact cache]'\
and added the '__at_files' function:
__at_files () {
compset -P #; _files
}
This may be very noobish, but for someone that has never encountered this before, I was pleased that this solved my problem, or so I thought.
This fails me if I have multiple '-e' parameters, which is totally a supported model (similar to how docker allows multiple -v or -p arguments). What this means is that the first '-e' parameter will have my prefixed completion work, but any '-e' parameters after that point become 'dumb' and only allow for normal '_files' completion from what I can tell. So the following will not complete properly:
ansible-playbook -e key=value -e #vars/file
but this would complete for the file itself:
ansible-playbook -e key=value -e vars/file
Did I mess up? I see the same type of behavior for this particular completion plugin's '-M' option (it also becomes 'dumb' and does basic file completion). I may have simply not searched for the correct terminology or combination of terms, or perhaps in the rather complicated documentation missed what covers this, but again, with only a few days experience digging into this, I'm lost.
If multiple -e options are valid, the _arguments specification should start with * so instead of:
"(-e --extra-vars)"{-e,--extra-vars}"[EXTR ....
use:
\*{-e,--extra-vars}"[EXTR ...
The (-e --extra-vars) part indicates a list of options that can not follow the one being specified. So that isn't needed anymore because it is presumably valid to do, e.g.:
ansible-playbook -e key-value --extra-vars #vars/file

What does $* mean in a make command?

There's a command in a batch file that I didn't write that reads:
make -f foo_mk $*
Printing * using the echo command gives me a list of the files in that folder i.e foo1_mk and foo1.mk. Calling the command does not appear to give the same output as though I called:
make -f foo1_mk $foo1_mk
make -f foo1_mk $foo1.mk
So what does $* mean in this context?
For GNU Makefiles
The body of a rule in a makefile has access to special variables, including $* which expands to the stem with which the pattern of the rule matches.
You can find a list of these automatic variables in the GNU Make Manual

AIX make/makefile : variable assignment is not working

Is there some trick with the standard AIX make tool to use dynamic variables?
I wish to make a different directory depending on the underlying hostname:
# makefile
thisHOSTNAME=`hostname`
all: $(thisHOSTNAME) makeMyDir
machine-1:
TMP_DIR=V1
machine-2:
TMP_DIR=V2
makeMyDir:
#echo makeMyDir TMP_DIR=$(TMP_DIR)
# mkdir -p $(TMP_DIR) !! NOT WORKING
On running "make all", it turns out that $TMP_DIR is empty!?
The dependency $(thisHOSTNAME) in the target all is resolved correctly, and the corresponding target is executed, but the variable TMP_DIR does not maintain the assigned value it would seem.
$ make all
TMP_DIR=V2
makeMyDir TMP_DIR=
The backtick syntax is shell syntax, not make syntax. You can use it as the value of variables that are used in commands, but you can't use it for a target name as in
thisHOSTNAME=`hostname`
all: $(thisHOSTNAME) makeMyDir
Understand that this becomes
all: `hostname` makeMyDir
and makes all depend on the target hostname including backticks (which I don't know how to insert here), since dependencies are specified in make syntax.
I'm not sure if AIX make allows to use the GNU make syntax which would permit
thisHOSTNAME = $(shell hostname)
If not, you might ponder converting the AIX makefile to a GNU makefile.
If you don't have the GNU make extensions (namely shell and if*), then it's going to get ugly:
# Makefile
all: makeMyDir
thisbox:
mkdir -vp thisdir
thatbox:
mkdir -vp thatdir
makeMyDir: $(HOSTNAME)
then inject environment variables on invocation:
$ HOSTNAME=$(hostname) make -e
References:
https://www.gnu.org/software/make/manual/html_node/Environment.html
https://www.gnu.org/software/make/manual/html_node/Options-Summary.html

What does autoload do in zsh?

I wasn't able to find a documentation for the widely used autoload command in zsh. Does anybody can explain it in plain English?
A bit more specific: What does autoloading of modules mean, for example in this line:
autoload -Uz vcs_info
What does it do?
I've tried autoload --help, man autoload, googling - no success. Thanks!
The autoload feature is not available in bash, but it is in ksh (korn shell) and zsh. On zsh see man zshbuiltins.
Functions are called in the same way as any other command. There can be a name conflict between a program and a function. What autoload does is to mark that name as being a function rather than an external program. The function has to be in a file on its own, with the filename the same as the function name.
autoload -Uz vcs_info
The -U means mark the function vcs_info for autoloading and suppress alias expansion. The -z means use zsh (rather than ksh) style. See also the functions command.
Edit (from comment, as suggested by #ijoseph):
So it records the fact that the name is a function and not an external program - it does not call it unless the -X option is used, it just affects the search path when it is called. If the function name does not collide with the name of a program then it is not required. Prefix your functions with something like f_ and you will probably never need it.
For more detail see http://zsh.sourceforge.net/Doc/Release/Functions.html.
autoload tells zsh to look for a file in $FPATH/$fpath containing a function definition, instead of a file in $PATH/$path containing an executable script or binary.
Script
A script is just a sequence of commands that get executed when the script is run. For example, suppose you have a file called hello like this:
echo "Setting 'greeting'"
greeting='Hello'
If the file is executable and located in one of the directories in your $PATH, then you can run it as a script by just typing its name. But scripts get their own copy of the shell process, so anything they do can't affect the calling shell environment. The assignment to greeting above will be in effect only within the script; once the script exits, it won't have had any impact on your interactive shell session:
$ hello
Setting 'greeting'
$ echo $greeting
$
Function
A function is instead defined once and stays in the shell's memory; when you call it, it executes inside the current shell, and can therefore have side effects:
hello() {
echo "Setting 'greeting'"
greeting='Hello'
}
$ hello
Setting 'greeting'
$ echo $greeting
Hello
So you use functions when you want to modify your shell environment. The Zsh Line Editor (ZLE) also uses functions - when you bind a key to some action, that action is defined as a shell function (which has to be added to ZLE with the zle -N command).
Now, if you have a lot of functions, then you might not want to define all of them in your .zshrc every time you start a new shell; that slows down shell startup and uses memory to store functions that you might not wind up calling during the lifetime of that shell. So you can instead put the function definitions into their own files, named after the functions they define, and put the files into directories in your $FPATH, which works like $PATH.
Zsh comes with a bunch of standard functions in the default $FPATH already. But it won't know to look for a command there unless you've first told it that the command is a function.
That's what autoload does: it says "Hey, Zsh, this command name here is a function, so when I try to run it, go look for its definition in my FPATH, instead of looking for an executable in my PATH."
The first time you run command which Zsh determines is autoloaded function, the shell sources the definition file. Then, if there's nothing in the file except the function definition, or if the shell option KSH_AUTOLOAD is set, it proceeds to call the function with the arguments you supplied. But if that option is not set and the file contains any code outside the function definition (like initialization of variables used by the function), the function is not called automatically. In that case it's up to you to call the function inside the file after defining it so that first invocation will work.

Is it possible to use wild characters to delete dataset on z/OS

I want to remove lots of temporary PS datasets with dataset name like MYTEST.**, but still can't find an easy way to handle the task.
I meant to use a Shell command below to remove them
cat "//'dataset.list'"| xargs -I '{}' tsocmd "delete '{}'"
However, first I have to save the dataset list into a PS dataset or Unix file. In Unix, we can redirect output of ls command into a text file: "ls MYTEST.* > dslist", but on TSO or ISPF panel, seems no simple command to do that.
Anyone has any clue on this? Your comment would be appreciated.
Rexx ISPF option is probably the easiest and can be used in the future, but options include:
Use the save command in ispf 3.4 to save to a file, then use a rexx program on the file created by the save command
listcat command, in particular
listcat lvl(MYTEST) ofile(ddname)
then write a rexx program to do the actual delete
Alternatively you can use the ISPF services LMDINIT, LMDLISTY & LMDFREE in a rexx program running under ISPF i.e.
/* Rexx ispf program to process datasets */
Address ispexec
"LMDINIT LISTID(lidv) LEVEL(MYTEST)"
"LMDLIST LISTID("lidv") OPTION(list) dataset(dsvar) stats(yes)"
do while rc = 0
/* Delete or whatever */
end
"LMDFREE LISTID("lidv")"
For all these methods you need to fully qualify the first High level qualifier.
Learning what Rexx / ISPF will serve you into the future. In the ISPF Editor, you can use the model command to get Templates / information for all the ISPF commands:
Command ====> Model LMDINIT
will add a template for the lmdinit command. There are templates for rexx, cobol, pl1, ISPF-panels, ISPF-skeletons messages etc.
Thanks Bruce for the comprehensive answer. According to Bruce's tips, I just worked out a one-line Shell command as below:
tsocmd "listcat lvl(MYTEST) " | grep -E "MYTEST(\..+)+" | cut -d' ' -f3 | xargs -I '{}' tsocmd "delete '{}'"
Above command works perfectly.
Update - The IDCAMS DELETE command has had the MASK operand for a while. You use it like:
DELETE 'MYTEST.**' MASK
Documentation for z/OS 2.1 is here.

Resources