Makefiles and understanding wildcards - makefile

So I'm trying to start using make on an existing project and I'm getting super confused as to how to properly use wildcards. or atleast that's what I think I need.
basically this is the command I'm trying to run fieldalignment ./**/*copy. copy would be a variable that would be passed into the command and basically I'm just trying to search the whole current directory and the subdirectories for that package and run the fieldalignment command against it. I'm working in go. from what I understand the '*' should be replace with wildcards? but I'm not entirely sure how.
this is the basic idea of what I'm trying to do.
checkfieldalignment:
fieldalignment ./...$(PACK)
fixfieldalignment :
fieldalignment -fix ./**/*$(PACK)
The first one kind of works but also gets an error 3. not sure what that means.

make implements standard POSIX-style globbing in its wildcard function, the same as the traditional shell globbing and the default globbing in shells like bash. And, when make invokes a shell to run a recipe it always invokes /bin/sh, not whatever shell the user happens to be running.
Make does not implement "extended" globbing such as that provided by zsh and some other shells, or available in bash if you turn it on.
And /bin/sh is a POSIX shell, or a link to another shell that is running in "POSIX mode", so it doesn't support extended globbing either.
So, special features like ** to mean "search all subdirectories" are not available here.
You can use the find program to replace it, like this:
fixfieldalignment :
fieldalignment -fix $$(find ./ -name '*$(PACK)')

Related

How to run csh script in bash shell

My default shell is bash in Ubuntu 14.04. I have a csh script file named clean.sh with the following make command:
#! /bin/csh -f
make -f commande.make del
And commande.make has
CKHOME=../CHEMKIN/DATA_BASES
LIN_DATA=${CKHOME}/LIN_FILES/
LINK_CKTP=${CKHOME}/LINK_CKTP_FILES/
#-----------------------------------------------------
include schema_cinetique.make
LINKFILE=${NAME}_LINK
LINKTPFILE=${NAME}_LINKTP
LINKFILE_OLD=${NAME_OLD}_LINK
LINKFILE_NEW=${NAME_NEW}_LINK
#-----------------------------------------------------
cplink :
${COPY} ${LINK_CKTP}${LINKFILE} LINK
cplink2 :
${COPY} ${LINK_CKTP}${LINKFILE} LINKZ1
tplink :
${COPY} ${LINK_CKTP}${LINKTPFILE} LINKTPZ1
calcul :
${COPY} jobtimp1 LJOBNZ1
${COPY} unsteadyf.dat1 DATZ1
del :
${DELETE} LINKZ1 LINKTPZ1 LJOBNZ1 DATZ1 SOLASUZ1
I opened the terminal and moved to the location and tried
./clean.sh
or
csh clean.sh &
or
csh -f clean.sh
Nothing worked.
I got the following line in the terminal,
LINKZ1 LINKTPZ1 LJOBNZ1 DATZ1 SOLASUZ1
make: LINKZ1: Command not found
make: *** [del] Error 127
So, how to run clean.sh file ?
You are confused. The Csh script contains a single command which actually runs identically in Bash.
#!/bin/bash
make -f commande.make del
Or, for that matter, the same with #!/bin/sh. Or, in this individual case, even sh clean.sh, since the shebang is then just a comment, and the commands in the file are available in sh just as well as in csh.
Once make runs, that is what parses and executes the commands in commande.make. make is not a "Fortran command", it is a utility for building projects (but the makefile named commande.make probably contains some instructions for how to compile Fortran code).
In the general case, Csh and Bash are incompatible, but the differences are in the shell's syntax itself (so, the syntax of loops and conditionals, etc, as well as variable assignments and various other shell builtins).
As an aside, Csh command files should probably not have a .sh extension, as that vaguely implies Bourne shell (sh) syntax. File extensions on Unix are just a hint to human readers, so not technically important; but please don't confuse them/us.
(As a further aside, nobody should be using Csh in 2022. There was a time when the C shell was attractive compared to its competition, but that was on the order of 40 years ago.)
The subsequent errors you are reporting seem to indicate that the makefile depends on some utilities which you have not installed. Figuring that out is a significant enough and separate enough question that you should probably ask a new question about that, probably with more debugging details. But in brief, it seems that make needs to be run with parameters to indicate what NAME and COPY (and probably some other variables) should be. Try with make -f commande.make COPY=cp DELETE=rm NAME=foobar for a start, but it's probably not yet anywhere near sufficient.
(I would actually assume that there will be a README file or similar to actually instruct you how to use commande.make since it seems to have some local conventions of its own.)
It seems the script is written having portability in mind, i.e. the name of the cp and rm binaries is kept in variables rather than hard-coding it. My best guess is that this has been done to make it possible to run the script on non UNIX systems, like Windows.
To make it work, export the respective variables before running the script. For the del action you are calling, only the DELETE variable is needed. It should be set to rm which is the command used to remove files on Linux:
export DELETE=rm
./clean.sh
Note: exporting the variable can also be done in one line when invoking the script, by prepending it to the command line:
DELETE=rm ./clean.sh
This behaviour is described in the bash manual:
The environment for any simple command or function may be augmented temporarily by prefixing it with parameter assignments, as described in Shell Parameters. These assignment statements affect only the environment seen by that command.

'which' command is incorrect

I have a shell script in my home directory called "echo". I added my home directory to my path, so that this echo would replace the other one.
To do this, I used: export PATH=/home/me:$PATH
When I do which echo, it shows the one I want. /home/me/echo
But when I actually do something like echo asdf it uses the system echo.
Am I doing something wrong?
which is an external command, so it doesn't have access to your current shell's built-in commands, functions, or aliases. In fact, at least on my system, /usr/bin/which is a shell script, so you can examine it and see how it works.
If you want to know how your shell will interpret a command, use type rather than which. If you're using bash, type -a will print all possible meanings in order of precedence. Consult your shell's documentation for details.
For most shells, built-in commands take precedence over commands in your $PATH. The whole point of having a built-in echo, for example, is that it's faster than loading /bin/echo into memory.
If you want your own echo command to override the shell's built-in echo, you can define it as a shell function.
On the other hand, overriding the built-in echo command doesn't strike me as a good idea in the first place. If it behaves the same as the built-in echo, there's not much point. If it doesn't, then it could break scripts that use echo expecting it to work a certain way. If possible, I suggest giving your command a different way. If it's an enhanced version of echo, you could even call it Echo.
It is likely using the shell's builtin.
If you want the one in your path you can do
`which echo` asdf
From this little article that explains the rules, here's a list in descending order of precedence:
Aliases
Shell functions
Shell builtin commands
Hash tables
PATH variable
echo is a shell builtin command (al least in bash) and PATH has the lowest priority. I guess you'll need to create a function or an alias.

Preprocess line before it is processed by bash

Is there a way to preprocess a line entered into bash in interactive mode before it is processed by bash?
I'd like to introduce some custom shorthand syntax to deal with long paths. For example, instead of writing 'cd /one/two/three/four/five', I'd like to be able to write something like 'cd /.../five', and then my preprocessing script would replace this by the former command (if a unique directory 'five' exists somewhere below /).
I found http://glyf.livejournal.com/63106.html which describes how to execute a hook function before a command is executed. However, the approach does not allow to alter the command to be executed.
There's no good way of doing this generally for all commands.
However, you can do it for specific commands by overriding them with a function. For your cd case, you can stick something like this in your .bashrc:
cd() {
path="$1"
[[ $path == "/.../five" ]] && path="/one/two/three/four/five"
builtin cd "$path"
}
In bash 4 or later, you can use the globstar option.
shopt -s globstar
cd /**/five
assuming that five is a unique directory.
The short answer is not directly. As you have found, the PROMPT_COMMAND environment variable allows you to issue a command before the prompt is displayed, which can allow for some very creative uses, e.g. Unlimited BASH History, but nothing that would allow you to parse and replace input directly.
What you are wanting to do can be accomplished using functions and alias within your .bashrc. One approach would be to use either findutils-locate or simply a find command to search directories below the present working directory for the last component in the ellipsed path, and then provide the full path in return. However, even with the indexing, locate would take a bit of time, and depending on the depth, find itself may be to slow for generically doing this for all possible directories. If however, you had a list of specific directories you would like to implement something like this for, then the solution would be workable and relatively easy.
To provide any type of prototype or further detail, we would need to know more about how you intent to use the path information, and whether multiple paths could be provided in a single command.
Another issue arises if the directory five is non-unique...

Source a script with a different shell type

Let's say a script is called with /bin/sh. Is it possible to source another script from that script and to have it be interpreted with #!/bin/bash?
It would appear that the #!/bin/bash doesn't do anything...
And by source, at this point I am meaning the functionality of manipulating the parent environment.
No. The whole point of sourcing a script is that the script is interpreted by the shell doing the sourcing. If, as is often the case, /bin/sh is bash, then you will get the desired behavior. Otherwise, you are out of luck.
Try the source command, or dot operator. You might also try the env command. Note, make sure you export if you're using source (or dot).

wildcard in scripts

It is fine to run
evince ./result/demo_1000000_10000*.ps
on a shell window. But when I put it into a scripts file, then run that file, it can not find all those files ./result/demo_1000000_10000*.ps... here * is meant to be a wildcard and following is the scripts.
evince ./result/demo_1000000_10000"*.ps"
So are there any changes that should be made when putting commands into scripts?
It should work the same way in a script or on the command line. The quotation marks prevent the wildcard from being expanded. Just remove them from the script. (Why did you add them in the first place?)
If the command runs from the prompt as shown, then it should also run from a shell script if the current directory of the invoking process is the same - with exactly the same notation. There is no reason to include quotes in the scripted version if you want it to do the same as the unscripted version. And if you ran the quoted version at the command line, it would fail the same as the quoted version in the scripted version does.
However, in a script, you do have to worry about whether the Postscript files you plan to work on are in the correct location. Sometimes, the script uses an absolute pathname, sometimes the script uses cd to change directory to the correct place, sometimes there's an argument or environment variable that locates the files.
So, if used carefully, you don't have to change anything for the script to work - but there are many ways you can prevent the script from working. One of those is by adding quotes around wildcard characters.

Resources