Shell Scripting: Using a variable to define a path - bash

My problem lies with my confusion with shell variables.
To my understanding, variables allow me to store a value (String in this case) and to call it later in my code. So if I wanted to have a variable that holds the path to some set of scripts, I could ideally just store it like this:
SPTH = '/home/Foo/Documents/Programs/ShellScripts/Butler'
//Later on in the script//
cd $SPTH
./script1
What I'm trying to do, with probably the wrong syntax, is to set the path to variable SPTH.
Then I use cd with argument $SPTH.
Ideally this would allow me to run the file there without typing in the path. However it doesn't work. The $SPTH is ignored and the result is as if cd was used alone.
So what am I doing wrong? And what would be a way to do this?

Don't use spaces...
(Incorrect)
SPTH = '/home/Foo/Documents/Programs/ShellScripts/Butler'
(Correct)
SPTH='/home/Foo/Documents/Programs/ShellScripts/Butler'

To add to the above correct answer :-
For my case in shell, this code worked (working on sqoop)
ROOT_PATH="path/to/the/folder"
--options-file $ROOT_PATH/query.txt

Related

Create shell alias with value from current path

I want to create a shell alias which would run
command ew --constantswitch --anotherconstantswitch <name>
Now the value name needs to be extracted from the current path. the current path looks like this
[username#path-to-shell-xxxxxxxx]/path/to/directory/with/name%
How can I create an alias such that when I run aliasX it will
Extract the name from current path (which is last value of the prompt)
Add this path to the command above and execute.
An alias may not be competent for the job, but a function surely do. Try this code:
myfunc() {
command ew --constantswitch --anotherconstantswitch "${PWD##*/}"
}
The trick is ${PWD##*/}. You know the automatic variable $PWD is exactly what you get when you run pwd, as well as Bash's builtin string substitution ${var##pattern} that removes pattern from the left of the variable with maximum match. So ${PWD##*/} removes everything except the name after the last slash, which as you described is what you're looking for.
In practice, a function is more versatile than an alias. If you still need to add extra arguments to the command, append "$#" to the end of the command inside the function, so any argument that you pass to the function will be forwarded to the command.
Since you're not trying to do anything involving arguments, an alias is actually possible:
alias aliasX='echo "${PWD##*/}"'
This will print the current directory name when you use aliasX. Or, using your example:
alias aliasX='command ew --constantswitch --anotherconstantswitch "${PWD##*/}"'
Notice that the alias must be in single quotes or $PWD will expand when you define it instead of when you use it.
For anything slightly more complex, you should use a function instead of an alias, as shown in iBug's answer.

Makefile 'for' variable as dynamic variable name

I have some dynamically named variables in Makefile. That all works and is fine.
Now I need to reference some of those variables in a for loop, but I can't seem to find the right syntax:
#for module in $(MODULES); do \
(echo $(SRC_$$module)); \
done
each $(MODULE) is a name that needs to be appended to $(SRC_.. for example $(SRC_foo) $(SRC_bar)... but I can't seem to do that with this syntax.
You have expansion-time issues. You can't expand make-level variables dynamically once the shell has started to run. Which is what you are trying to do here.
You either expand the variables at make time or at shell time but not both.
To expand everything at make time you can use something like this.
#$(foreach module,$(MODULES),$(foreach cfile,$(SRC_$(module)),echo '[$(cfile)]';))
Expanding at shell time is possible but a bit messier/trickier.

How to declare variable in a script that will belong to the caller

as the title say, I have many variables, like 200, and I'd like to have a script just containing the declarations, appart from my bash with execute code. Would it be possible with my bash that execute code to just call a script that create the variable and that exist after?
EDIT : The site proposed that answer the questions explain the same situation, however there are really good details the people who answered here gave.
When the declarations are in /usr/local/lib/myvars, start your script (after the SHEBANG line) with sourcing that file using the dot notation:
. /usr/local/lib/myvars
When you have so much vars, you must have a lot of code and some general functions. Put those in one file and include that one:
. /usr/local/lib/my_utils
And know you might be wondering: 2 includes in every scriptfile? No, you can source the myvars file in the my_utils file.
Be aware you are introducing global variables, they can be changed everywhere.
You can export the variables to be available externally and source that file.
Example. Contents of variables.sh
export VARIABLE1=Value1
export VARIABLE2=Value2
.
.
export VARIABLE200=Value200
Contents of main script:
#!/bin/bash
source /Pathtosourcefile/variables.sh
echo $VARIABLE1
This would print out:
Value1

Variable PATH in shell using cron

I've read that while using a cron you define variables like always:
var = <value>
But you can't use variable values on < value > such as:
PATH=$PATH
So how could I introduce the PATH inside PATH plus HOME/FOLDER for instance? Normally I would do...
PATH=$HOME/FOLDER:$PATH
But if what I've read is correct, that isn't available...right?
my crontab(5) page agrees with you:
The value string is not parsed for environmental substitutions or replacement of variables, thus lines like
PATH = $HOME/bin:$PATH
will not work as you might expect.
However, if you're specifically interested in $HOME, you can use this:
An alternative for setting up the commands path is using the fact that many shells will treat the tilde(~) as substitution of $HOME, so if you use bash for your tasks you can use this:
SHELL=/bin/bash
PATH=~/bin:/usr/bin/:/bin

Defining recursively expanded variable with same name as environment variable

I'm trying to lazily evaluate configuration option. I want to issue a Make error only if the variable is actually used (substituted).
Consider the following Makefile:
VAR = $(error "E")
NFS_DIR = NFS_DIR is $(VAR)
T = $(NFS_DIR) is 1
all:
echo Test
If I run it with my environment (which has /srv/nfs value), the output is following:
➜ ~ make
echo Test
Makefile:3: *** "E". Stop.
So the recursive definition acts like simple definition.
If I clear the environment, it works as expected:
➜ ~ env -i make
echo Test
Test
I couldn't find any mention that recursively-expanded variable, when defined with same name as environment variable, will act like simply-expanded variable.
So the questions are:
Why the observed behavior?
How to implement the desired behavior?
Update: to clarify — I don't want to use ?= since the options are configuration options I want them to come strictly from Makefile and not from environment.
Any variable which is in the environment when make starts, will be exported to the environment of any command make runs (as part of a recipe, etc.) In order for make to send the value of the variable to the command, make first has to expand it. It's not acting like a simply-expanded variable. It's just that running a command forces the expansion.
This is kind of a nasty side-effect but I'm not sure there's anything that can be done directly: this behavior is traditional and mandated by POSIX and lots of makefiles would break if it were changed.
You have two choices I can think of. The first is to use the unexport make command to tell make to not send that variable in the command's environment.
The second is to change the name of the variable in make to something that is not a valid environment variable: make will only export variables whose names are legal shell variables (contain only alphanumeric plus _). So using a name like VAR-local instead of VAR would do it.
The question appear to be extremely clear in the title but the actual request get lost in details so the only other reply left it mostly unanswered. Directly answering to the question in the title, which is very interesting, to define a variable in a Makefile with same name as environment variable you can get its value with printenv:
PATH=${shell printenv PATH}:/opt/bin
echo:
echo $(PATH)
Other techniques to achieve the same result without relying on evaluation with external commands are welcome.

Resources