expected fi bug in bash script - bash

The following bash script creates a directory if not exists and writes a file to it. Now, if directory exists, it retrieves a list of files of this directory encapsulated in an array. This is the code:
if [ -d $ETC_DIR ]; then
echo " * wan27 has been found on your system"
echo " * checking for installed versions"
versions=( `ls $ETC_DIR` ) # line 27
else
echo " * First time installation! Creating etc directory now..."
mkdir $ETC_DIR
echo "$VERSION\n$USERi\n`date +%Y%m%d%H%M%S`\n$ROOT_DIR" > $ETC_DIR/install_$VERSION.txt
fi
And this is what the terminal outputs:
27: Syntax error: "(" unexpected (expecting "fi")
So, line 27 actually is this one in first excerpt of code:
versions=( `ls $ETC_DIR` )
What am I doing wrong? I've tried added semi-colons as well but ended up with the same result...

Your script relies on a Bash feature (creating an array using assignment with parentheses), but it's being run by the Bourne shell.
Change the first line of your script to:
#!/bin/bash

Related

ShellScript not working on Pre-session-command (PowerCenter)

The goal is to check the existence of a file and create a blank file if this doesn't exist, using Shell Script on the Pre-session-command (Informatica PowerCenter) like the code below:
ParamDirTrabalho=/dir/powercenter/project1
ParamArq=file.csv
ParamQtdArq=`cat ${ParamDirTrabalho}/${ParamArq} | wc -l`
if [ $ParamQtdArq == 0 ];then touch ${ParamDirTrabalho}/${ParamArq};fi
This is the error:
Message: [Pre/Post Session Command] Process id 10683. Standard output and error:
sh: line 2:
: command not found
cat: /dir/powercenter/project1
/file.csv
: No such file or directory
sh: line 4:
: command not found
I can execute successfully when pointing to a sh file with the code above. But I need to write the code inside the pre-session-command.
Please enclose parameters by double quotes.
ParamDirTrabalho="/dir/powercenter/project1"
ParamArq="file.csv"
Also pls make sure you provide RWX permission to folders.
You cannot get the WC from a file if it doesn't exist at all. That's what the error is "No such file or directory" if I understand it right. What you need to do is check if file exists or not rather than the count and then touch if it doesn't exist.
if [ ! -f filename ];then touch filename; fi
or
if [ -f filename ];then exit 0; else touch filename; fi

script file not found when using source

I have a bash script in a file named reach.sh.
This file is given exe rights using chmod 755 /Users/vb/Documents/util/bash/reach.sh.
I then created an alias using alias reach='/Users/vb/Documents/util/bash/reach.sh'
So far this works great.
It happens that I need to run this script in my current process, so theoretically I would need to add . or source before my script path.
So I now have alias reach='source /Users/vb/Documents/util/bash/reach.sh'
At this point when I run my alias reach, the script is failing.
Error /Users/vb/Documents/util/bash/reach.sh:7: = not found
Line 7 if [ "$1" == "cr" ] || [ "$1" == "c" ]; then
Full script
#!/bin/bash
# env
REACH_ROOT="/Users/vb/Documents/bitbucket/fork/self"
# process
if [ "$1" == "cr" ] || [ "$1" == "c" ]; then
echo -e "Redirection to subfolder"
cd ${REACH_ROOT}/src/cr
pwd
else
echo -e "Redirection to root folder"
cd ${REACH_ROOT}
pwd
fi
Any idea what I could be missing ?
I'm running my script in zsh which is not a bash shell, so when I force it to run in my current process it runs in a zsh shell and does not recognize bash commands anymore.
In your question, you say "It happens that I need to run this script in my current process", so I'm wondering why you are using source at all. Just run the script. Observe:
bash-script.sh
#!/bin/bash
if [ "$1" == "aaa" ]; then
echo "AAA"
fi
zsh-script.sh
#!/bin/zsh
echo "try a ..."
./bash-script.sh a
echo "try aaa ..."
./bash-script.sh aaa
echo "try b ..."
./bash-script.sh b
output from ./zsh-script.sh
try a ...
try aaa ...
AAA
try b ...
If, in zsh-script.sh, I put source in front of each ./bash-script.sh, I do get the behavior you described in your question.
But, if you just need to "run this script in my current process", well, then ... just run it.
source tries to read a file as lines to be interpreted by the current shell, which is zsh as you have said. But simply running it, causes the first line (the #!/bin/bash "shebang" line) to start a new shell that interprets the lines itself. That will totally resolve the use of bash syntax from within a zsh context.

How to delay a command substitution in a shell script?

I have a bash script that in a nutshell generates a file via other command (works fine) and then later in the script I do a wc command on the file generated. My problem is that i'm using command substitution on the wc command and when I execute the script it is executing this substitution immediately rather than waiting for the file to be generated earlier in the script. What are my options?
The script is a shell program to run Oracle SQLLoader to load data into an Oracle Table. The SQLLoader command generates a file with rejected records and I am trying to do a word count on it. This is my code:
#!/bin/sh
# Set variables
program_name="My Program Name"
input_dir="/interface/inbound/hr_datafile"
log_dir="/interface/inbound/log"
bad_dir="/interface/inbound/hr_bad"
archive_dir="/interface/inbound/hr_archive"
input_base="Import_20171213"
input_ext="csv"
control_file="data_loader.ctl"
exit_status=0
d=`date "+%Y%m%d"`
t=`date "+%H%M"`
# Check if data file exists, count records
if [ -f ${input_dir}/${input_base}*.${input_ext} ]; then
data_file_name=`ls -1rt ${input_dir}/${input_base}*.${input_ext} | head -1 | cut -c 32-100`
data_file_base=${data_file_name%.*}
echo "Data file name: " ${data_file_name}
echo "Data file base: " ${data_file_base}
no_of_recs=`expr $(wc -l ${input_dir}/${data_file_name} | cut -c 1-8) - 1`
echo "DEBUG no_of_recs: " ${no_of_recs}
no_of_errs=0
else
echo
echo
echo
echo "----------------------------- ${program_name} ------------------------------------------"
echo "----------------------------------- Error report : ------------------------------------------------"
echo
echo "Please place your Data files in the UNIX directory => "${input_dir}
echo "${program_name} Process exiting ..."
echo
echo "---------------------------------------------------------------------------------------------------"
echo
echo
echo
echo
echo
exit 1
fi
# Run SQL*Loader
echo
echo "==> Loading Data...into MY_TABLE table"
echo
# Create a temporary control file to pass the data file name in
cat $XX_TOP/bin/${control_file} | sed "s/:FILENAME/${data_file_name}/g" > $XX_TOP/bin/${data_file_base}_temp.ctl
# NOTE: The following sqlldr format is used to "hide" the oracle user name and password
sqlldr errors=100000 skip=1 control=$XX_TOP/bin/${data_file_base}_temp.ctl data=${input_dir}/${data_file_name} log=${log_dir}/${data_file_base}.log bad=${bad_dir}/${data_file_base}.bad <<-END_SQLLDR > /dev/null
apps/`cat ${DB_SCRIPTS}/.${ORACLE_SID}apps`
END_SQLLDR
exit_status=$?
echo "DEBUG exit_status " ${exit_status}
# Remove temporary control file
rm -rf $XX_TOP/bin/${data_file_base}_temp.ctl
# Check for Errors
if [ -f ${bad_dir}/${data_file_base}.bad ]; then
echo
echo "----------------------------- ${program_name} ------------------------------------------"
echo "----------------------------------- Error report : ------------------------------------------------"
echo
grep 'Record' ${log_dir}/${data_file_base}.log > ${log_dir}/${data_file_base}.rec
grep 'ORA' ${log_dir}/${data_file_base}.log > ${log_dir}/${data_file_base}.err
paste ${log_dir}/${data_file_base}.rec ${log_dir}/${data_file_base}.err ${bad_dir}/${data_file_base}.bad
echo
echo "<---------------------------------End of Error Report---------------------------------------------->"
echo
# Count error records
no_of_errs=$(wc -l ${bad_dir}/${data_file_base}.bad | cut -c 1-8)
no_of_recs=$(expr ${no_of_recs} - ${no_of_errs})
# Remove temp files
rm ${log_dir}/${data_file_base}.rec
rm ${log_dir}/${data_file_base}.err
rm ${bad_dir}/${data_file_base}.bad
else
echo "Bad File not found at ${bad_dir}/${data_file_base}.bad"
fi
if (( ${no_of_errs} > 0 )); then
echo "Error found in data file..."
exit_status=1
else
# Archive the data file if no errors
mv ${input_dir}/${data_file_name} ${archive_dir}/${data_file_base}_$d"_"$t.${input_ext}
echo "Data file archived to ${archive_dir}"
exit_status=0
fi
echo
echo
echo
echo "----------------------------- ${program_name} ------------------------------------------"
echo
echo "Total records errored out :" ${no_of_errs}
echo "Total records successfully read :" ${no_of_recs}
echo "---------------------------------------------------------------------------------------------------"
echo
# Final Exit Status
if [ ${exit_status} -eq 1 ]; then
echo "==> Exiting process...Status : ${exit_status}"
exit 1
fi
The file referenced in the if condition check is the file generated, so I'm checking if the file exists and then running the wc on it. I know that it's executing prematurely because this wc error appears in my script output before it should:
Data file name: Import_20171213.csv
Data file base: Import_20171213
DEBUG no_of_recs: 27
==> Loading Data...into MY_TABLE table
wc: 0653-755 Cannot open /interface/inbound/hr_bad/Import_20171213.bad.
Username:
SQL*Loader: Release 10.1.0.5.0 - Production on Thu Dec 21 12:42:39 2017
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Commit point reached - logical record count 27
Program exited with status 2
In the code, the wc command on the .bad file is performed after the sqlldr section, yet the log shows the error occurring before sqlldr is invoked.
Any ideas would be much appreciated! Thanks!
You aren't seeing all of the output you expect - anything after the call to SQL*Loader is missing - and the error from wc is coming in the wrong place, before instead of after the Username; prompt. But it shouldn't be erroring giving the construct you've used - if the file doesn't exist the if test should stop that line being reach.
The issue is that it isn't seeing the end of the heredoc. All of the commands beyond the start of the heredoc are being executed as part of the heredoc processing but aren't going anywhere or being displayed to the terminal (as expected), and something in the way that is all being evaluated is causing the wc to run unexpectedly, even though the file doens't exist. You're seeing the stderr output from that.
And that is all happening before SQL*Loader starts, so you see the Username: prompt from that afterwards.
From comments it seems the heredoc-ending END_SQLLDR is really indented in your actual code, which isn't reflected in the posted question. As you used the <<- heredoc form that implies it's indented with spaces rather than tabs. That is causing that to not be recognised as the end of the here doc.
From The Linux Documentation Project:
The closing limit string, on the final line of a here document, must start in the first character position. There can be no leading whitespace. Trailing whitespace after the limit string likewise causes unexpected behavior. The whitespace prevents the limit string from being recognized.
Removing the whitespace so that is the first thing on the line will fix it.

How to get bash to ignore file-not-founds

In a (ba)sh script, how do I ignore file-not-found errors?
I am writing a script that reads a (partial) filename from stdin, using:
read file; $FILEDIR/$file.sh
I need to give the script functionality to reject filenames that don't exist.
e.g.
$UTILDIR does NOT contains script.sh
User types script
Script tries to access $UTILDIR/script.sh and fails as
./run.sh: line 32: /utiltest/script.sh: No such file or directory
How do I make the script print an error, but continue the script without printing the 'normal' error?
You can test whether the file exists using the code in #gogaman's answer, but you are probably more interested in knowing whether the file is present and executable. For that, you should use the -x test instead of -e
if [ -x "$FILEDIR/$file.sh" ]; then
echo file exists
else
echo file does not exist or is not executable
fi
if [ -e $FILEDIR/$file.sh ]; then
echo file exists;
else
echo file does not exist;
fi
Here we can define a shell procedure that runs only if the file exists
run-if-present () {
echo $1 is really there
}
[ -e $thefile ] && run-if-present $thefile
Depending on what you do with the script, the command will fail with a specific exit code. If you are executing the script, the exit code can be 126 (permission denied) or 127 (file not found).
command
if (($? == 126 || $? == 127))
then
echo 'Command not found or not executable' > /dev/stderr
fi

Quick bash script to run a script in a specified folder?

I am attempting to write a bash script that changes directory and then runs an existing script in the new working directory.
This is what I have so far:
#!/bin/bash
cd /path/to/a/folder
./scriptname
scriptname is an executable file that exists in /path/to/a/folder - and (needless to say), I do have permission to run that script.
However, when I run this mind numbingly simple script (above), I get the response:
scriptname: No such file or directory
What am I missing?! the commands work as expected when entered at the CLI, so I am at a loss to explain the error message. How do I fix this?
Looking at your script makes me think that the script you want to launch a script which is locate in the initial directory. Since you change you directory before executing it won't work.
I suggest the following modified script:
#!/bin/bash
SCRIPT_DIR=$PWD
cd /path/to/a/folder
$SCRIPT_DIR/scriptname
cd /path/to/a/folder
pwd
ls
./scriptname
which'll show you what it thinks it's doing.
I usually have something like this in my useful script directory:
#!/bin/bash
# Provide usage information if not arguments were supplied
if [[ "$#" -le 0 ]]; then
echo "Usage: $0 <executable> [<argument>...]" >&2
exit 1
fi
# Get the executable by removing the last slash and anything before it
X="${1##*/}"
# Get the directory by removing the executable name
D="${1%$X}"
# Check if the directory exists
if [[ -d "$D" ]]; then
# If it does, cd into it
cd "$D"
else
if [[ "$D" ]]; then
# Complain if a directory was specified, but does not exist
echo "Directory '$D' does not exist" >&2
exit 1
fi
fi
# Check if the executable is, well, executable
if [[ -x "$X" ]]; then
# Run the executable in its directory with the supplied arguments
exec ./"$X" "${#:2}"
else
# Complain if the executable is not a valid
echo "Executable '$X' does not exist in '$D'" >&2
exit 1
fi
Usage:
$ cdexec
Usage: /home/archon/bin/cdexec <executable> [<argument>...]
$ cdexec /bin/ls ls
ls
$ cdexec /bin/xxx/ls ls
Directory '/bin/xxx/' does not exist
$ cdexec /ls ls
Executable 'ls' does not exist in '/'
One source of such error messages under those conditions is a broken symlink.
However, you say the script works when run from the command line. I would also check to see whether the directory is a symlink that's doing something other than what you expect.
Does it work if you call it in your script with the full path instead of using cd?
#!/bin/bash
/path/to/a/folder/scriptname
What about when called that way from the command line?

Resources