BASH Unexpected EOF - bash

My Mac keeps telling my unexpected end of file for this bash script, on the last line. I am not new to programming but very new to BASH, does anyone see anything wrong with this?
#!/bin/bash
#bootstrapper.sh
PIDD="$5"
while sleep 1; do kill -0 $PIDD || break; done
# Absolute path to this script. /home/user/bin/foo.sh
SCRIPT=$(readlink -f $0)
# Absolute path this script is in. /home/user/bin
SCRIPTPATH=`dirname $SCRIPT`
POSPAR1="$1" #-l
POSPAR2="$2" #location
POSPAR3="$3" #-d
POSPAR4="$4" #directory
cp -r -f $SCRIPTPATH/$4/* $2
rm -r -f $SCRIPTPATH/$4
Thank you in advance!

I coped your code from the question on a Mac (copy'n'paste) and ran the file with:
bash -n -v x.sh
In fact, I did that twice; the first time, I ensured there was a newline at the end of the file, and the second time I ensured that there wasn't a newline. And bash was quite happy both times.
This indicates to me that the problem is not in the visible characters; there are some invisible characters in the file causing grief. You will probably need to scrutinize the file with a tool such as od -c to find the character that is causing the trouble.
Also, FWIW, the readlink command on my Mac gives:
$ readlink -f $0
readlink: illegal option -- f
usage: readlink [-n] [file ...]
$
The Linux version of readlink takes -f. It isn't a POSIX command, so there is no de jure standard to refer to.

Analyzing the file with od -c revealed the line ending were \r\n, I did modify the file one Windows, silly me. Anyway, I am having another issues with the BASH script. This line:
while sleep 1; do kill -0 $PIDD || break; done
Is supposed to wait until the PID (stored in variable $PIDD) closes. It waits until it doesn't exist (the PID), but when it finally doesn't exist, it outputs: kill: 4: No such process. The rest of the script works as intended, but then the script doesn't terminate. Can I make the script terminate properly and not have that No such process be outputted?
Sorry for all the newbie questions, I'm awful at BASH and Linux.
Thanks again for all your help.

Related

command substitution not working in alias?

I wanted to make an alias for launching a vim session with all the c/header/makefiles, etc loaded into the buffer.
shopt -s extglob
alias vimc="files=$(ls -A *.?(c|h|mk|[1-9]) .gitconfig [mM]akefile 2>/dev/null); [[ -z $files ]] || vim $files"
When I run the command enclosed within the quotations from the shell, it works but when run as the alias itself, it does not. Running vimc, causes vim to launch only in the first matched file(which happens to be the Makefile) and the other files(names) are executed as commands for some reason(of course unsuccessfully). I tried fiddling around and it seems that the command substitution introduces the problem. Because running only the ls produces expected output.
I cannot use xargs with vim because it breaks the terminal display.
Can anyone explain what might be causing this ?
Here is some output:
$ ls
Makefile readme main.1 main.c header.h config.mk
$ vimc
main.1: command not found
main.c: command not found
.gitignore: command not found
header.h: command not found
config.mk: command not found
On an related note, would it be possible to do what I intend to do above in a "single line", i.e without storing it into a variable files and checking to see if it is empty, using only the output stream from ls?

Bash: Path to symlink which calls this script

I have the following situation:
I have a script with a path of: /usr/local/bin/rsnapshot.period
I want to have symlinks to it in various /etc/cron.[period]/ directories, like /etc/cron.hourly/rsnapshot
I'd like to have the script look up the full path to the symlink, and pull out the [period] part, so I can feed it to rsnapshot.
I can do all the text hacking. The problem I'm having trouble with is getting the path to the calling symlink from within the bash script. $0 seems to point to /usr/local/bin/rsnapshot.period
Is there a better way to get this info?
$0 seems to point to /usr/local/bin/rsnapshot.period
$0 is set by the calling program in its exec*() call, as the first word of the arg argument or the first element of the argv argument. If you feel that the tool you're using is setting this value incorrectly then you should open a bug with the developer.
In the meantime, using a hardlink instead of a symlink will allow you to detect the script name properly, but will break if you aren't careful with the tool you use to edit the main script.
Turns out my problem wasn't that $0 was incorrect - it was pointing to the right place. However, as I was trying to get the absolute path of it, I was using 'realpath' before it, which resolved symlinks.
Passing realpath the '-s' fixed it. Here's my test script and the output of it:
Script:
#!/bin/sh
echo \$0: $0
echo realpath -s \$0: $(realpath -s $0)
echo readlink -e: $(readlink -e $0)
Executed:
$0: ./rsnapshot
realpath -s $0: /etc/cron.hourly/rsnapshot
readlink -e: /usr/local/bin/rsnapshot.period

Shell Scripting - Must not generate extra messages and its not but says I am

There is a similar question about this issue. But not the same solution.
I am to create a shell script that takes two parameters:
1.the desired file extension
2.the name of a single file to be renamed with that extension
The script should rename the file with the desired file extension. If the file does not exist, it should print out "fileName: No such file". It is producing this message but the professor's tests says it is producing unexpected messages(extra messages) but it is not. My shell script is:
#!/bin/sh
fileExtension="$1"
shift
oldName="${#}"
extension=${oldName##*.}
if test -r "$oldName"
then
if "$fileExtension" == $oldName.*
then
echo "$oldName"
else
newName="${oldName%.*}.$fileExtension"
mv "$oldName" "$newName"
fi
else
echo "$oldName": No such file
fi
Everytime I test it, it produces "fileName: no such file" and nothing else.
The test is executed by
./chExt2.sh cpp aardvark.CPP
where aardvark.CPP is not on the directory.
Any help or guidance would be much appreciated. Thank you
Your shebang is telling your shell to use /bin/sh to run the script. /bin/sh is typically a symlink to the real/default shell on the host. For example, mine's bash:
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar 27 2009 /bin/sh -> bash
It sounds like your professor's computer's /bin/sh is using a different shell than you are [expecting]. This script runs fine in ksh or bash, for example, but produces "extra output" if /bin/sh is tcsh:
fileExtension=cpp: Command not found.
Illegal variable name.

How to backup filesystem with tar using a bash script?

I want to backup my ubuntu filesystem, and I wrote this little script. It is very basic, but being my first try I am afraid to do mistakes. And since it will take few hours to complete to see results, I think it is better to ask you as experienced programmers if I did something wrong.
I'm particularly interested in > will that record output of mv or will it output also results of tar?
Also variables inside tar command is it correct way?
#!/bin/bash
mybackupname="backup-fullsys-$(date +%Y-%m-%d).tar.gz"
{ time tar -cfpzv $mybackupname --exclude=/$mybackupname --exclude=/proc --exclude=/lost+found --exclude=/sys --exclude=/mnt --exclude=/media --exclude=/dev / && ls -gh $mybackupname && mv -v $mybackupname backups/filesystem/ ; } > backup-system.log
exit
Anything I should know before I run this?
Sandro, you might want to consider spacing things out in your script and producing individual errors. Makes things much easier to read.
#!/bin/bash
mybackupname="backup-fullsys-$(date +%Y-%m-%d).tar.gz"
# Record start time by epoch second
start=$(date '+%s')
# List of excludes in a bash array, for easier reading.
excludes=(--exclude=/$mybackupname)
excludes+=(--exclude=/proc)
excludes+=(--exclude=/lost+found)
excludes+=(--exclude=/sys)
excludes+=(--exclude=/mnt)
excludes+=(--exclude=/media)
excludes+=(--exclude=/dev)
if ! tar -czf "$mybackupname" "${excludes[#]}" /; then
status="tar failed"
elif ! mv "$mybackupname" backups/filesystem/ ; then
status="mv failed"
else
status="success: size=$(stat -c%s backups/filesystem/$mybackupname) duration=$((`date '+%s'` - $start))"
fi
# Log to system log; handle this using syslog(8).
logger -t backup "$status"
If you wanted to keep debug information (like the stderr of tar or mv), that could be handled with redirection to a tmpfile or debug file. But if the command is being run via cron and has output, cron should send it to you via email. A silent cron job is a successful cron job.
The series of ifs causes each program to be run as long as the previous one was successful. It's like chaining your commands with &&, but lets you run other code in case of failure.
Note that I've changed the order of options for tar, because the thing that comes after -f is the file you're saving things to. Also, the -p option is only useful when extracting files from a tar. Permissions are always saved when you create (-c) a tar.
Others might wish to note that this usage of the stat command works in GNU/Linux, but not other unices like FreeBSD or Mac OSX. In BSD, you'd use stat -f%z $mybackupname.
The file redirection as you have it will only record the output of mv.
You can do
{ tar ... && mv ... ; } > logfile 2>&1
to capture the output of both, plus any errors that may occur.
It's a good idea to always be in the habit of quoting variables when they are expanded.
There's no need for the exit.

Bash syntax error: unexpected end of file

Forgive me for this is a very simple script in Bash. Here's the code:
#!/bin/bash
# june 2011
if [ $# -lt 3 -o $# -gt 3 ]; then
echo "Error... Usage: $0 host database username"
exit 0
fi
after running sh file.sh:
syntax error: unexpected end of file
I think file.sh is with CRLF line terminators.
run
dos2unix file.sh
then the problem will be fixed.
You can install dos2unix in ubuntu with this:
sudo apt-get install dos2unix
Another thing to check (just occured to me):
terminate bodies of single-line functions with semicolon
I.e. this innocent-looking snippet will cause the same error:
die () { test -n "$#" && echo "$#"; exit 1 }
To make the dumb parser happy:
die () { test -n "$#" && echo "$#"; exit 1; }
i also just got this error message by using the wrong syntax in an if clause
else if (syntax error: unexpected end of file)
elif (correct syntax)
i debugged it by commenting bits out until it worked
an un-closed if => fi clause will raise this as well
tip: use trap to debug, if your script is huge...
e.g.
set -x
trap read debug
I got this answer from this similar problem on StackOverflow
Open the file in Vim and try
:set fileformat=unix
Convert eh line endings to unix endings and see if that solves the
issue. If editing in Vim, enter the command :set fileformat=unix and
save the file. Several other editors have the ability to convert line
endings, such as Notepad++ or Atom
Thanks #lemongrassnginger
This was happening for me when I was trying to call a function using parens, e.g.
run() {
echo hello
}
run()
should be:
run() {
echo hello
}
run
I had the problem when I wrote "if - fi" statement in one line:
if [ -f ~/.git-completion.bash ]; then . ~/.git-completion.bash fi
Write multiline solved my problem:
if [ -f ~/.git-completion.bash ]; then
. ~/.git-completion.bash
fi
So I found this post and the answers did not help me but i was able to figure out why it gave me the error. I had a
cat > temp.txt < EOF
some content
EOF
The issue was that i copied the above code to be in a function and inadvertently tabbed the code. Need to make sure the last EOF is not tabbed.
on cygwin I needed:-
export SHELLOPTS
set -o igncr
in .bash_profile . This way I didn't need to run unix2dos
FOR WINDOWS:
In my case, I was working on Windows OS and I got the same error while running autoconf.
I simply open configure.ac file with my NOTEPAD++ IDE.
Then I converted the File with EOL conversion into Windows (CR LF) as follows:
EDIT -> EOL CONVERSION -> WINDOWS (CR LF)
Missing a closing brace on a function definition will cause this error as I just discovered.
function whoIsAnIidiot() {
echo "you are for forgetting the closing brace just below this line !"
Which of course should be like this...
function whoIsAnIidiot() {
echo "not you for sure"
}
I was able to cut and paste your code into a file and it ran correctly. If you
execute it like this it should work:
Your "file.sh":
#!/bin/bash
# june 2011
if [ $# -lt 3 -o $# -gt 3 ]; then
echo "Error... Usage: $0 host database username"
exit 0
fi
The command:
$ ./file.sh arg1 arg2 arg3
Note that "file.sh" must be executable:
$ chmod +x file.sh
You may be getting that error b/c of how you're doing input (w/ a pipe, carrot,
etc.). You could also try splitting the condition into two:
if [ $# -lt 3 ] || [ $# -gt 3 ]; then
echo "Error... Usage: $0 host database username"
exit 0
fi
Or, since you're using bash, you could use built-in syntax:
if [[ $# -lt 3 || $# -gt 3 ]]; then
echo "Error... Usage: $0 host database username"
exit 0
fi
And, finally, you could of course just check if 3 arguments were given (clean,
maintains POSIX shell compatibility):
if [ $# -ne 3 ]; then
echo "Error... Usage: $0 host database username"
exit 0
fi
In my case, there is a redundant \ in the like following:
function foo() {
python tools/run_net.py \
--cfg configs/Kinetics/X3D_8x8_R50.yaml \
NUM_GPUS 1 \
TRAIN.BATCH_SIZE 8 \
SOLVER.BASE_LR 0.0125 \
DATA.PATH_TO_DATA_DIR ./afs/kinetics400 \
DATA.PATH_PREFIX ./afs/kinetics400 \ # Error
}
There is NOT a \ at the end of DATA.PATH_PREFIX ./afs/kinetics400
I just cut-and-pasted your example into a file; it ran fine under bash. I don't see any problems with it.
For good measure you may want to ensure it ends with a newline, though bash shouldn't care. (It runs for me both with and without the final newline.)
You'll sometimes see strange errors if you've accidentally embedded a control character in the file. Since it's a short script, try creating a new script by pasting it from your question here on StackOverflow, or by simply re-typing it.
What version of bash are you using? (bash --version)
Good luck!
Make sure the name of the directory in which the .sh file is present does not have a space character. e.g: Say if it is in a folder called 'New Folder', you're bound to come across the error that you've cited. Instead just name it as 'New_Folder'. I hope this helps.
Apparently, some versions of the shell can also emit this message when the final line of your script lacks a newline.
In Ubuntu:
$ gedit ~/.profile
Then, File -> Save as and set end line to Unix/Linux
I know I am too late to the party. Hope this may help someone.
Check your .bashrc file. Perhaps rename or move it.
Discussion here: Unable to source a simple bash script
For people using MacOS:
If you received a file with Windows format and wanted to run on MacOS and seeing this error, run these commands.
brew install dos2unix
sh <file.sh>
If the the script itself is valid and there are no syntax errors, then some possible causes could be:
Invalid end-of-lines (for example, \r\n instead of \n)
Presence of the byte order mark (BOM) at the beginning of the file
Both can be fixed using vim or vi.
To fix line endings open the file in vim and from the command mode type:
:set ff=unix
To remove the BOM use:
:set nobomb
For those who don't have dos2unix installed (and don't want to install it):
Remove trailing \r character that causes this error:
sed -i 's/\r$//' filename
Details from this StackOverflow answer. This was really helpful.
https://stackoverflow.com/a/32912867/7286223

Resources