This question already has answers here:
How to get a variable value if variable name is stored as string?
(10 answers)
Closed 2 years ago.
I have 2 files.
One is list file named envlist.
Another one is shell script file named test.
In envlist(list file), there's the environment variable list as below ;
setup_top
CFG
those are already declared as the environment variable.
(So when I type cd $setup_top or cd $CFG in command, it works well)
And in test(shell script), there's the code as below ;
#!/bin/bash
dir=$(<$env/envlist) # $env is another environment variable I declared.
for i in ${dir[*]}
do
cd $i # I think this line is a matter.
echo "------------------"
sleep 2
done
When I executed this shell script, I got the error as below;
./test: line 6: cd: setup_top: No such file or directory
----------------------------
./test: line 6: cd: CFG: No such file or directory
----------------------------
reading envlist file line by line seems to work well, but cd command seems not to work.
How can I fix the shell script code to work fine?
Actually, you need to transform $i into the name of the variable, then read $varname. If the shell would support this, you should write cd $$i. Unfortunately, this will not work, because $$ gives the current PID.
As suggested by #Biffen, you should use shell variable substitution:
cd ${!i}
Previous answer, using dangerous eval instruction:
eval cd \$$i
Note: eval is a dangerous instruction. Use it only if you are sure of the content of your files (not files provided by untrusted users).
Related
This question already has answers here:
Make a Bash alias that takes a parameter?
(24 answers)
Closed 4 months ago.
I am trying to create an alias in my bash profile such that I can call
backup_dir Playground
and have it complete:
cp -r Playground $HOME/BACKUP
I would also like to ensure that if the file/directory is of the same name it is just overwritten.
The code I input in my bash_profile is as follows:
alias backup='cp $2 $HOME/BACKUP/$2'
alias backup_dir='cp -r $2 $HOME/BACKUP/$2'
I also tried it with $1 but it did not work either.
What actually occurs is that it copies the contents of my backup directory and creates it in the directory I'm supposed to be copying/copying from.
Aliases don't really take arguments, and trying to define aliases as if they did winds up in strange territory (if you define a simple alias 'foo' that just echos instead of copies, you'll find it reversed the order of the arguments you passed - i.e. the first argument is the backup directory and the second is the directory you wanted.) I'm guessing the details of why that happens aren't super interesting to you - but that is... 'expected'.
The solution is to write a function to use in your alias, or to write a small shell script and call that instead.
Aliases really substitute 'bash' as the command that then executes the string you pass (if you echo $0 instead of $1, you'll see something like 'bash foo' as the output).
More detailed instructions can be found in the ubuntu forums (for example)
This question already has answers here:
How to use aliases defined in .bashrc in other scripts?
(6 answers)
Closed 2 years ago.
I'm using a Mac and I have this alias defined in .bashrc:
$cat .bashrc | grep la
alias la='ls -la'
then I try to use it in a script:
$cat ./mytest.sh
#!/bin/bash
la
It runs and says it cannot find la:
./mytest.sh: line 2: la: command not found
Why is this? I tried on both Mac and Linux, same error!
Your .bashrc is only used by interactive shells. https://www.gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files says:
Invoked non-interactively
When Bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute. Bash behaves as if the following command were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
but the value of the PATH variable is not used to search for the filename.
As noted above, if a non-interactive shell is invoked with the --login option, Bash attempts to read and execute commands from the login shell startup files.
As you can see, there's nothing about .bashrc there. Your alias simply doesn't exist in the script.
But even if .bashrc were read, there's another problem:
Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt.
So if you wanted aliases to work in a script, you'd have to do shopt -s expand_aliases first. Or just use a shell function instead of an alias:
la() {
ls -la
}
The simplest answer is to fix this issue is to do the 2 important things in your script -or it wont' work, if you just do one thing.
#!/bin/bash -i
# Expand aliases defined in the shell ~/.bashrc
shopt -s expand_aliases
After this, your aliases that you have defined in ~/.bashrc they will be available in your shell script (giga.sh or any.sh) and to any function or child shell within such script.
If you don't do that, you'll get an error:
your_cool_alias: command not found
At the beginning of the ~/.bashrc file usually can be found two lines as:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
This line aborts the inclusion for scripts which is not recommended anyway. For portability issues, you usually write the full command or define the alias in the script itself.
This question already has answers here:
Why can't I change directories using "cd" in a script?
(33 answers)
Closed 6 years ago.
I am trying to create a script whereby I have list of numerical test folders and want users to be able to cd into one of them after inputting the folder number.
The script correctly concatenates the input but on running the script it does not actually execute the cd command to the required directory?
It echo's to the screen but then just sits there as if awaiting a further prompt?
Can anyone advise what I am missing please? Script 'chgdir' is as below:
#!/bin/bash
#
# Script to move to test##dir (using input from user for dir number)
echo "Enter test directory number as ## and hit Return"
read dirnum
echo "cd /home/John/test$dirnum""dir"
However on running the script outputs the command to the screen but does not 'cd' and just remains in ~/bin?
cd /home/John/test01dir
John#John-PC ~/bin
P.S I am completely new to bash scripting as you can tell so any help really appreciated.
All your script does is to echo the command that you formed. You need to actually execute the cd command as well as just echoing it.
cd /home/John/test ${dirnum}dir
The {} around the variable name allows the shell to distinguish the variable name from the extra characters appended after it.
That will change the directory inside the script. To have it apply afterwards, you will need to source the script (with dot "." or "source") to affect the shell you are running in.
Your script just prints the command. That's all the echo command does. It doesn't execute it, because you didn't tell it to.
You could execute the cd command by replacing the echo command with this:
cd "/home/John/test${dirnum}dir"
But if that's the last line of your script, it won't do anything useful. Doing a cd inside a script doesn't affect anything but the script itself.
If you want to cd from a script and have it take effect in the invoking shell, you can source the script rather than executing it:
. ./thescript
or you can have the script print the command you want to execute and eval its output:
eval "`./thescript`"
(To be clear, if you source the script using the . command, it needs to execute the cd command; if you val its output, the script needs to print the command.)
I am looking to execute a script but have it include another script before it executes. The problem is, the included script would be generated and the executed script would be unmodifiable. One solution I came up with, was to actually reverse the include, by having the include script as a wrapper, calling set to set the arguments for the executed script and then dotting/sourcing it. E.g.
#!/bin/bash
# Generated wrapper or include script.
: Performing some setup...
target_script=$1 ; shift
set -- "$#"
. "$target_script"
Where target_script is the script I actually want to run, importing settings from the wrapper.
However, the potential problem I face is that callers of the target script or even the target script itself may be expecting $0 to be set to the path of it's location on the file system. But because this wrapper approach overrides $0, the value of $0 may be unexpected and could produce undefined behaviour.
Is there another way to perform what is in effect, an LD_PRELOAD but in the scripted form, through bash without interfering with its runtime parameters?
I have looked at --init-file or --rcfile, but these only seem to be included for interactive shells.
Forcing interactive mode does seem to allow me to specify --rcfile:
$ bash --rcfile /tmp/x-include.sh -i /tmp/xx.sh
include_script: $0=bash, $BASH_SOURCE=/tmp/x-include.sh
target_script: $0=/tmp/xx.sh, $BASH_SOURCE=/tmp/xx.sh
Content of the x-include.sh script:
#!/bin/bash
echo "include_script: \$0=$0, \$BASH_SOURCE=$BASH_SOURCE"
Content of the xx.sh script:
#!/bin/bash
echo "target_script: \$0=$0, \$BASH_SOURCE=$BASH_SOURCE"
From the bash documentation:
When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in
the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read
and execute. Bash behaves as if the following command were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
but the value of the PATH variable is not used to search for the file name.
So that settles it then:
BASH_ENV=/tmp/x-include.sh /bin/bash /tmp/xx.sh
This question already has answers here:
Bash syntax error: unexpected end of file
(21 answers)
Closed 8 years ago.
If I set a variable in a shell script and then try to use it to create another variable, it doesn't seem to get substituted correctly. Example:
#!/bin/bash
X=/software/xxx
echo variable X = $X
echo path using variable: $X/yyy
echo path without variable: /software/xxx/yyy
This outputs:
variable X = /software/xxx
/yyy using variable: /software/xxx
path without variable: /software/xxx/yyy
I had expected the second output line to be:
path using variable: /software/xxx/yyy
I have tried various combinations of quotes and using ${X}, but all to no avail.
I'm new to shell scripting (coming from a Windows background), so I'm sure there is something really simple that I'm missing here.
In case anyone wonders why I want to do this, the background to this is that I need to write a shell script that takes a relative pathname parameter, determines its absolute pathname, then sets CLASSPATH with a number of jar files in that directory before invoking a Java program:
#!/bin/bash
DIR=`readlink -fn $1`
export CLASSPATH=$DIR/x.jar:$DIR/y.jar
java progname
You have carriage return (CR) character at the end of your X= variable declaration:
#!/bin/bash
X=/software/xxx^M
echo variable X = $X
echo path using variable: $X/yyy
(where ^M represents ONE special character - CR). I assume your editor doesn't show it. Try to open your script with vim. Windows and Linux marks newline in a different way (check wiki) . I suppose you're using some Windows editor.
Please read Bash Pitfalls webpage. I'm sure you can learn a lot from there.
btw. one way to enter ^M at vim: go to insert-mode i, than press: CTRL+k, M, ENTER