I'm bad at bash programming. Where is the error? Here is my .profile file:
# WARNING: For help understanding this file, and before you try
# to change any of it, type "man .profile" and read carefully.
#
#
# Set command search rules
#
if [ -x /bin/showpath ] ; then
export PATH; PATH=`/bin/showpath $HOME/bin /u/cs350/sys161/bin /software/gnu/bin standard`
export PATH; PATH=`/bin/showpath usedby=user standard $HOME/bin`
#
# Find out what kind of terminal we are using
#
eval `setterm sytek:kd404 default:vc404`
#
# Set terminal-type dependent options (e.g. sysline or prompt string)
#
#HOMEHOST="<hostname>"
#HOMEUSER="<userid>"
#export HOMEHOST HOMEUSER
PS1="$ "
#
# Now do the usual signing on things
#
export MAIL; MAIL=${MAIL-"/usr/spool/mail/$USER"}
if [ -r /software/.admin/bins/bin/read_system_news ] ; then /software/.admin/bins/bin/read_system_news ; fi
EOF
Your first if is missing a fi.
You are missing a fi at the end of file add it.
Also get rid of EOF. The EOF in your case is treated as a command.
Sometimes running your script using different shells gives you a clue about the error.
When we run your program using:
sh it says Syntax error: end of
file unexpected (expecting "fi")
csh it says if: Expression
Syntax.
Related
I am a beginner with bash and I'm using an open source file which have this sentence ./wallet balance at the end of the file , Could any body tell me what dose it mean ?! here's the code inside the opensource file :
#!/usr/bin/env bash
C_RED="\033[31;01m"
C_GREEN="\033[32;01m"
C_YELLOW="\033[33;01m"
C_BLUE="\033[34;01m"
C_PINK="\033[35;01m"
C_CYAN="\033[36;01m"
C_NO="\033[0m"
################################################################################
### MAIN #######################################################################
################################################################################
if [[ ${#} -gt 0 ]]; then
printf "${C_RED}balance does not require any argument.\n"
printf "${C_YELLOW}usage: ${C_NO}%s\n" "balance"
exit 1
fi
./wallet balance
it means run the command called "wallet" which is to be found in the current directory "./" and provide it with a single parameter "balance".
I use the term "command" above, but in linux it could be lots of thins, for example it could be an excutable script such as a shell script, a compiled program (e.g. C) an alias etc.
I would like to setup some files for development, staging and production with environment variables, for example:
application_root/development.env
KEY1=value1
KEY2=value2
There would be similar files staging.env and production.env.
I am looking for a couple different bash scripts which would allow the loading of all these variables in either development or staging/production.
In local development I want to effectively run export KEY1=value1 for each line in the file.
For staging/production I will be deploying to Heroku and would like to effectively run heroku config:set -a herokuappname KEY1=value1 for each line in the staging or production.env files.
I know there are some gems designed for doing this but it seems like this might be pretty simple. I also like the flexibility of having the .env files as simple lists of keys and values and not specifically being tied to any language/framework. If I would have to change something about the way these variables need to be loaded it would be a matter of changing the script but not the .env files.
In the simplest form, you can load the key-value pairs into a bash array as follows:
IFS=$'\n' read -d '' -ra nameValuePairs < ./development.env
In Bash v4+, it's even simpler:
readarray -t nameValuePairs < ./development.env
You can then pass the resulting "${nameValuePairs[#]}" array to commands such as export or heroku config:set ...; e.g.:
export "${nameValuePairs[#]}"
Note, however, that the above only works as intended if the input *.env file meets all of the following criteria:
the keys are syntactically valid shell variable names and the lines have the form <key>=<value>, with no whitespace around =
the lines contain no quoting and no leading or trailing whitespace
there are no empty/blank lines or comment lines in the file.
the values are confined to a single line each.
A different approach is needed with files that do not adhere to this strict format; for instance, this related question deals with files that may contain quoted values.
Below is the source code for a bash script named load_env (the .sh suffix is generally not necessary and ambiguous):
You'd invoke it with the *.env file of interest, and it would perform the appropriate action (running heroku config:set … or export) based on the filename.
However, as stated, you must source the script (using source or its effective bash alias, .) in order to create environment variables (export) visible to the current shell.
To prevent obscure failures, the script complains if you pass a development.env file and have invoked the script without sourcing.
Examples:
./load_env ./staging.dev
. ./load_env ./development.dev # !! Note the need to source
load_env source code
#!/usr/bin/env bash
# Helper function that keeps its aux. variables localized.
# Note that the function itself remains defined after sourced invocation, however.
configOrExport() {
local envFile=$1 doConfig=0 doExport=0 appName
case "$(basename "$envFile" '.env')" in
staging)
doConfig=1
# Set the desired app name here.
appName=stagingapp
;;
production)
doConfig=1
# Set the desired app name here.
appName=productionapp
;;
development)
doExport=1
;;
*)
echo "ERROR: Invalid or missing *.env file name: $(basename "$envFile" '.env')" >&2; exit 2
esac
# Make sure the file exists and is readable.
[[ -r "$envFile" ]] || { echo "ERROR: *.env file not found or not readable: $envFile" >&2; exit 2; }
# If variables must be exported, make sure the script is being sourced.
[[ $doExport -eq 1 && $0 == "$BASH_SOURCE" ]] && { echo "ERROR: To define environment variables, you must *source* this script." >&2; exit 2; }
# Read all key-value pairs from the *.env file into an array.
# Note: This assumes that:
# - the keys are syntactically valid shell variable names
# - the lines contain no quoting and no leading or trailing whitespace
# - there are no empty/blank lines or comment lines in the file.
IFS=$'\n' read -d '' -ra nameValuePairs < "$envFile"
# Run configuration command.
(( doConfig )) && { heroku config:set -a "$appName" "${nameValuePairs[#]}" || exit; }
# Export variables (define as environment variables).
(( doExport )) && { export "${nameValuePairs[#]}" || exit; }
}
# Invoke the helper function.
configOrExport "$#"
I have little scripting experience. I have tried a new script to loop through multiple subdirectories and edit a file if the subdirectory exists. Here is the code I've failed with after multiple attempts, but I cannot resolve the for loop error:
!#/usr/din/sh
for domain in {PGBWAHS_NA PGBWAHS04_NA PGBWAHD_NA PGBWAHD04_NA PGBWAHQ_NA PGBWAHQ02_NA PGBWAHQ03_NA PGBWAHQ04_NA PGBWAHP_NA PGBWAHP02_NA PGBWAHP03_NA PGBWAHP04_NA
do
echo "$domain this is the current domain from the array"
cd /opt/tibco/tra/domain/$domain
echo `pwd` "this is the directory after cd command"
cp hawkagent.cfg hawkagent.cfg.back
sed 's/-scan_rate 10/-scan_rate 30/' hawkagent.cfg
Done
____________________
Error message returned:
$ ./modify_log_scan_rate.sh
./modify_log_scan_rate.sh[3]: Syntax error at line 3 : `for' is not matched.
Remove the opening curly braces after in: for domain in *{*PGBWAHS_NA ...
Done needs to be done (case matters).
– Etan Reisner
I am trying to set some Windows environment variables in Perl with case sensitivity in order to use them in a shell script.
However, I noticed that the environment variables are all in uppercase when I try to use them in lowercase in a shell script called from Perl with system command and run with Msys.
For example, the following script:
#!perl
system "echo echo TOTO=\$TOTO > toto.sh";
system "echo echo Titi=\$Titi >> toto.sh";
system "echo echo TITI=\$TITI >> toto.sh";
$ENV{'TOTO'}="0+0";
$ENV{'Titi'}="Not toto!";
system("sh toto.sh");
returns (while run in Msys) the following output:
TOTO=0+0
Titi=
TITI=Not toto!
Does anybody know whether this is possible in Windows (i.e. how to set the environment variable Titi and not TITI)?
Thanks
Windows environment variable identifiers are case-independent in the same way as Windows files.
Titi and TITI are both names for the same variable, and its value can be acccessed through either $ENV{TITI} or $ENV{Titi} in Perl. Likewise echo %TITI% and echo %Titi% on the command line will give the same result.
If you explain why it is that you need case-sensitive environment variable names then we may be able to help you.
The following should apply independently of the casing problem.
Let's take the first line:
system "echo echo TOTO=\$TOTO > toto.sh";
If you call
echo echo TOTO=\$TOTO
on your command line, the output will be:
echo TOTO=\$TOTO
which seems to be, what you want.
However, the line you are calling with system is first interpreted by perl, so your escaped \$ becomes a $.
The output then depends on the current value of $TOTO (before you set the environment variable in the script), which is probably empty.
You should change all those system calls to be single quoted:
system 'echo echo TOTO=\$TOTO > toto.sh';
If you do this, you will get the following output:
TOTO=0+0
Titi=
TITI=not TOTO
Titi is empty, because you didn't assign a value to it.
It appeared to be that it is not possible to do: Windows will only use the uppercase variables.
The way I did was to temporarily transform the script by replacing variables with their upper-case equivalent and switch them back to the previous state after using them.
In my case, I had to deal with the variables exported from the shell script Run_Session.sh. I have created a Perl script to perform the uppercase replacement and this is the result.
###############################
## SUBROUTINE uc_variables ##
#-----------------------------#
# This subroutine convert the environment variables exported
# by the top level script to upper case, and can revert the operation.
#
# Input:
# -----
# $mode: "ON" (default) or "OFF"
#
# Output:
# ------
# N/A
#-----------------------#
#########################
sub uc_variables {
my $mode=shift;
chdir $Bin;
if ($mode eq "OFF") {
foreach my $bak (glob "{*,*/*}.sh.bak") {
(my $orig = $bak)=~s/\.bak//;
move($bak,$orig);
}
} else {
#Check if back-up already exists
uc_variables("OFF") if (-e "Run_Session.sh.bak");
#List variables to update
my %uc_var;
open RUN_SESSION,"<Run_Session.sh" or die "Error while reading Run_Session.sh ($!)\n";
map { /export\s+(\w*[a-z]\w*)/ and ($uc_var{$1}=uc($1))=~s/Directory/DIR/i } <RUN_SESSION>;
close RUN_SESSION;
#Replace variables
foreach my $shell (glob "{*,*/*}.sh") {
#Back-up
copy($shell,"$shell.bak");
#Read data
open SHELL,"<$shell" or die "Error while reading $shell ($!)\n";
my $SHELL = join("", <SHELL>);
close SHELL;
#Replace
map { $SHELL=~s/$_/$uc_var{$_}/g } keys %uc_var;
#Print
open SHELL,">$shell" or die "Error while writing in $shell ($!)\n";
print SHELL $SHELL;
close SHELL;
}
}
} #end of uc_variables
I am trying to write a bash-script which will create a certain number of files which are passed into an argument, and also fill that file with relevant information. However, for some reason I can't get it to work properly, and googling turned up nothing.
I want it to create files like the following:
FileName:
Prob_3_ch_17.cpp
Filled as the following:
/*
User: Johnny Smith
Prob: 3
Output:
*/
Where the first command line argument is the chapter number. The second is the starting number, and the third is the ending number. So if the following is ran
sh ../FileMaker.sh 17 1 10
It will make 10 files, each filled with the appropriate data and proper file names, for chapter 17. This is the script that I came up with.
#!/bin/bash
# Syntax:
# $1 = Chapter Number
# $2 = Starting Number
# $3 = Ending Number
CHAPTER=$1
FIRST=$2
LAST=$3
U_NAME="Johnny Smith"
# Name: Prob_$NUMBER_Ch_$1.cpp
for ((NUMBER=$FIRST; $NUMBER<=$LAST; $NUMBER++));
do
if [ -e "Prob_$NUMBER_Ch_$CHAPTER.cpp" ]; then
echo "File Prob_$NUMBER_Ch_$CHAPTER.cpp already exists!"
else
echo "/* \n User: $U_NAME \n Problem: $NUMBER \n Output: \n */" >> "Prob_$NUMBER_Ch_$CHAPTER.cpp"
done
However, it doesn't run. I get the following error:
../FileMaker.sh: line 21: syntax error near unexpected token `done'
../FileMaker.sh: line 21: `done'
I've googled and found other people have had the same problem, but I didn't fully understand what was meant in the solution. Can someone please help me? I'm not the best at shell scripting, and I'm trying to learn by making scripts like this.
Thanks in advanced.
Syntax for if block and for-loop is wrong. correct syntax would be -
for ((NUMBER=FIRST; NUMBER<=LAST; NUMBER++));
do
if [ -e "Prob_$NUMBER_Ch_$CHAPTER.cpp" ]; then
echo "File Prob_$NUMBER_Ch_$CHAPTER.cpp already exists!"
else
echo "/* \n User: $U_NAME \n Problem: $NUMBER \n Output: \n */" >> "Prob_$NUMBER_Ch_$CHAPTER.cpp"
fi
done
See example 11.12 for c style for loop.
To create files use "Prob_"$NUMBER"Ch"$CHAPTER".cpp" at all the places.
Most shells allow a set -x at the top. This show you tracing of the script as it executes.
You need a trailing fi to close the if statement.
Shell math need NUMBER=$(expr $NUMBER + 1), it doesn't understand $NUMBER++.
You might find the printf command more handy than echo.
You will still have your variable use wrong in the loop and are only creating one file. I hope you can figure that out as this seems like homework.