Why would a bash script produce the error "command not founde"? - bash

What is wrong with the 5th line in this script ( I have included the snippet that gives me the error and the actual error is listed in the bottom after the code and a link to complete script)?
#! /bin/bash
INSTALLDIR=/usr/local/mapguideopensource
CLEAN_FLAG=0
while [ $# -gt 0 ]; do # Until you run out of parameters...
case "$1" in
-prefix|--prefix)
INSTALLDIR="$2"
shift
;;
-clean|--clean)
CLEAN_FLAG=1
shift
;;
-help|--help)
echo "Usage: $0 (options)"
echo "Options:"
echo " --prefix [installation directory]"
echo " --clean [clean all objects and binaries in Oem]"
echo " --help [Display usage]"
exit
;;
esac
shift # Check next set of parameters.
done
This is the error i get when i run this bash script on linux (REHL5) :
: command not founde 4:
: command not founde 8:
: command not founde 8:
: command not founde 12:
MapGuide Open Source build script for OEM components
'/build_oem.sh: line 17: syntax error near unexpected token `in
'/build_oem.sh: line 17: ` case "$1" in
Please note, that the line number above corresponds to the actual script i am running (i have included a link to that script below)
The original script i am running

From the errors, I'm pretty sure you have carriage returns (aka CR or ^M) at the end of the lines. Windows/DOS text files have carriage return AND linefeed at the end of each line, but unix programs (like bash) just expect a linefeed, and get horribly confused if there's a CR as well. The giveaway is error messages like:
: command not founde 4:
What this really is is ./build_oem.sh: line 4: ^M: command not found, but the carriage return makes the terminal go back to the beginning of the line, and write the end of the message over the beginning of the message:
./build_oem.sh: line 4:
: command not found
|
V
: command not founde 4:
To fix the script, use dos2unix to convert it to proper unix format, then switch to a text editor that saves in unix format.

What choroba says, but also note that your shebang has to be on the first line (which it is not), otherwise it is useless since it's just a plain comment then and it won't necessarily execute under bash.

In the original script, lines 4 and 8 are empty. There is probably some invisible control character on the lines. Try xxd build_oem.sh.

Related

shell process and compare array element

There is a file called test.txt that contains:
ljlkfjdslkfldjfdsajflkjf word:test1
dflkdjflkdfdjls word:test2
dlkdj word:test3
word:test4
word:NewYork
dljfldflkdflkdjf word:test7
djfkd word:young
dkjflke word:lisa
amazonwle word:NewYork
dlksldjf word:test10
Now all we want is to get the strings after colon and if the result is same, print the output, in this case it is "NewYork"
Here is the script which lists the elements but when tried to push into array and compare it is failing, Please let me know my mistakes.
#!/usr/bin/sh
input="test.txt"
cat $input | while read line; do output= $(echo $line | cut -d":" -f2); done
for (( i = 0 ; i < "${#output[#]}" ; i++ ))
{
echo ${output[i]}
}
Error obtained:
./compare.sh
./compare.sh: line 11: test1: command not found
./compare.sh: line 11: test2: command not found
./compare.sh: line 11: test3: command not found
./compare.sh: line 11: test4: command not found
./compare.sh: line 11: NewYork: command not found
./compare.sh: line 11: raghav: command not found
./compare.sh: line 11: young: command not found
./compare.sh: line 11: lisa: command not found
./compare.sh: line 11: NewYork: command not found
./compare.sh: line 11: test10: command not found
Please let me know my mistakes.
output= $(..) first excutes the command $(..) inside and grabs it's output. It then sets the variable output to an empty string as-if the same as output="" and exports the variable output and executes the output of $(..) as a command. Remove the space after =.
You are setting output on the right side of a pipe inside a subshell. The changes will not be visible outside - output is unset once the pipe terminates. Use redirection while .... done < file.
And output is not an array, but a normal variable. There is no ${output[i]} (well, except ${output[0]}) as it's not an array (and output is unset, as explained above). Append an element to an array output+=("$(...)").
#!/usr/bin/sh - is invalid, sh may not be bash and support bash arrays. To use bash extension specifically use bash and use a shebang with bash - #!/bin/bash,
Now stylistic:
The format for .... { ... } is supported in bash since forever, however it's a rather undocumented syntax rather to be deprecated to be readable by people used to programming in C. Prefer the standard do ... done.
The expansions $input and ${output[i]} are unquoted.
The read will ignore leading and trailing whitespaces and also interpret/ignore \ backslash sequences (ie. see -r option to read).
echo $line will make $line undergo word splitting - multiple whitespaces will be replaced by a single space.
And using cut after read can be simpler written as just read with IFS=: and splitting on read. Also, if you're using cut, you could just cut -d: -f2 file on the whole file instead of cutting one line at a time.
Re-read basic bash introduction - notice that bash is space aware, spaces around = count. Read bashfaq how to read a file field by field, read about subshells and environments, read bashfaq I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates? Or, why can't I pipe data to read? and an introduction to bash arrays.

Shell script print line number when it errors out

I have been looking for a way to print the line number inside the shell script when it errors out.
I came across '-x' option, which prints the line when running the shell script, but this is not exactly what I want. Maybe I could do $LINENO before every exit code? Is there a cleaner way to do it?
I just wanted the line number so I could open the shell script and directly go to the place where the interpreter realized the error.
Using
PS4=':$LINENO+'
will add line number to the output of set -x.
If you only want to print that on errors, there's some risk of running into bugs in recent interpreters. However, you can try the following (first given in this previous answer):
error() {
local parent_lineno="$1"
local message="$2"
local code="${3:-1}"
if [[ -n "$message" ]] ; then
echo "Error on or near line ${parent_lineno}: ${message}; exiting with status ${code}"
else
echo "Error on or near line ${parent_lineno}; exiting with status ${code}"
fi
exit "${code}"
}
trap 'error ${LINENO}' ERR
Again, this will not work on some recent builds of bash, which don't always have LINENO set correctly inside traps.
Another approach (which will only work on recent shells; the below uses some bash 4.0 and 4.1 features) is to use PS4 to emit the exit status and line number of each command to a dedicated file descriptor, and use tail to print only the last line given to that FD before the shell exits:
exec {BASH_XTRACEFD}> >(tail -n 1) # send set -x output to tail -n 1
PS4=':At line $LINENO; prior command exit status $?+'
set -x

'\r': command not found [duplicate]

This question already has answers here:
'\r': command not found - .bashrc / .bash_profile [duplicate]
(17 answers)
Closed 5 years ago.
echo "Select your option:"
echo "1. Change ip address"
echo "2. Add route"
echo "3. Reboot"
echo "4. Exit"
read A
case $A in
1)
echo "Add Ip address"
read IP
echo "Add Netmask"
read Netid
echo "Add name of interface"
read Interface
ifconfig ${Interface} ${IP}/${Netid}
if [ $? -ne 0 ];then
echo "Ip address not configured"
fi
;;
2)
echo "Add Destination"
read dst
echo "Add Netmask"
read Netid
echo "Add Gateway"
read gw
route add $dst mask $Netid gw $gw
if [ $? -ne 0 ];then
echo "Route not added"
fi
;;
3)
reboot
;;
4)
echo "Bye"
exit 0
;;
default)
echo "Wrong selection"
exit 1
esac
Error:
[b104#b104 Downloads]$ ./NetworkUtility.sh
./NetworkUtility.sh: line 1: $'\r': command not found
Select your option:
1. Change ip address
2. Add route
3. Reboot
4. Exit
1
': not a valid identifier 7: read: `A
./NetworkUtility.sh: line 8: $'\r': command not found
./NetworkUtility.sh: line 9: syntax error near unexpected token `newline'
'/NetworkUtility.sh: line 9: `case $A in
[b104#b104 Downloads]$
It seems that you have Windows style line endings (\r\n) - you need to change them to unix style (\n). If you have dos2unix installed you could use it. You could also do it using sed or awk.
Its End of Line(EOL) conversion issue when script is written in windows using some editors like notepad, notepad++(tested).
Sed , tr may solve the issue in case of you just need to run script, however if you are developing shell script its become annoying each time first convert using, sed/tr command then run your script.
Notepad++ has an option to convert END OF LINE CONVERSION(EOL).
How to do that:
go to Edit > EOL Conversion > select Unix/OSX
Here you go, save script file and run it.
Here is screenshot of the same
The error happens, because shell doesn't understand DOS/Windows-like line endings and it expects LF instead of CRLF.
You'll need to first configure your editor to use Unix-like line endings or use dos2unix command to change it automatically, e.g.
dos2unix ./NetworkUtility.sh
Read more details at: '\r': command not found.
If you're using Vagrant, check: Windows CRLF to Unix LF Issues in Vagrant

Syntax error near unexpected token 'elif'

#!/bin/bash
if [ "$1" = "boot" ]
then
if [ -f /var/log/boot.log ]
then
echo /var/log/boot.log
elif [ -f /var/log/boot ]
then
echo /var/log/boot
fi
fi
This shows the output:
: command not foundline 8: GetLogfileName.sh: line 15: syntax error
near unexpected token `elif' 'etLogfileName.sh: line 15: `
elif [ -f /var/log/boot ]
What is going wrong here?
The garbled error message indicates your file has carriage returns before the newline. Did you edit your script on Windows? Either use your text editor to save the file without carriage returns or run the script through dos2unix (or perhaps d2u)
If you are using vi editor, set ":set ff=unix", save the file, and re-execute it.
This file format (ff) set command tells vi to use LF-only line endings when the file is saved.

Looping through files bash script

I am trying to run a simple loop through all files script but it's giving me the following error. The script is called test.sh and I am using Cygwin on Windows 7.
My script:
#!/bin/bash
FILES = "/bowtie-0.12.7-win32/bowtie-0.12.7/output_635_25bp/*"
for f in $FILES
do
echo "hello world"
done
The error is:
./test.sh: line 2: FILES: command not found
./test.sh: line 4: syntax error near unexpected token ``$'do\r''
./test.sh: line 4: ``do
Before running the script I converted all the files in folder to unix format using dos2unix command.
Try:
for f in `ls /bowtie-0.12.7-win32/bowtie-0.12.7/output_635_25bp/*`; do echo "hello world"; done
Thanks!
Brandon
Collating other folks' answers into a single one.
You've two problems with this script:
The script still has Windows line endings (that's what the \r refers to; it's the character that Windows has in its line endings, but Unix doesn't). bcarlso pointed that one out. Run dos2unix over the script to sort it out.
When assigning variables in a bash script, you cannot have spaces around the = sign. scibuff caught that one.
The below gets interpreted as trying to run the command FILES (which doesn't exist) with the arguments = "/bowtie...".
FILES = "/bowtie-0.12.7-win32/bowtie-0.12.7/output_635_25bp/*"
Whereas the below is interpreted as assigning "/bowtie..." to the variable FILES:
FILES="/bowtie-0.12.7-win32/bowtie-0.12.7/output_635_25bp/*"
try
FILES=/bow.../*
for f in $FILES
do
echo "hello world"
done
i.e. no spaces around ' = '
Try to use the find-command
for i in `find /bow.../ -type f`
do
echo "hello world"
done
because ls will return directories too.
http://infofreund.de/bash-loop-through-files/
I have same the error:
./test.sh: line 2: FILES: command not found
./test.sh: line 4: syntax error near unexpected token $'do\r'' ./test.sh: line 4: do
I fixed it by change the ends line from 'CR LF' to 'LF' on the Cygwin when I run it on the windows

Resources