Tcl script cannot be executed from bash shell script - bash

I have a relatively strange problem with bash shell scripts and tcl scripts, invoked from within the shell scripts.
In perspective, I have a shell script that generates some other shell scripts, as well as tcl scripts. Some of the generated shell scripts invoke tcl scripts with tclsh command.
The files are created and stored in a directory, also created by the initial shell scripts, that generates the files and the folders where these are to be stored.
The problem is with the generated shell scripts, which invoke tclsh to run a tcl script. Even if the files are generated and the shell scripts have the permissions to be executed, the response from the shell is that the tcl file embedded in the shell script cannot be found.
However, the file exists and I can open it with both vi and gedit, RHEL 9.0 or Centos 5.7 platforms. But, when I take the same shell script out of the created directory, this error does not appear. Can you please suggest any idea? I checked also directory permissions, but they seem ok. I also checked the shell script for extra characters, but I did not find anything.

It's hard to tell what exactly is going wrong from your description; you leave out all the information actually required to diagnose the problem precisely. However…
You have a tclsh on your PATH, but your script isn't running despite being chmodded to be executable? That means that there's a problem with your #! line. Current best practice is that you use something like this:
#!/usr/bin/env tclsh
That will search your PATH for tclsh and use that, and it's so much easier than any of the alternative contortions.
The other thing that might be causing a problem is if your Tcl program contains:
package require Tcl 8.5
And yet the version of Tcl used by the tclsh on the path is 8.4. I've seen this a number of times, and if that's your problem you need to make sure that the right Tcl rpm is installed and to update your #! line to this:
#!/usr/bin/env tclsh8.5
Similarly for Tcl 8.6, but in that case you might need to build your own from source as well and install that in a suitable location. (Tcl 8.6 is still only really for people who are specialists.)
(The issue is that RHEL — and Centos too, which tracks RHEL — is very conservative when it comes to Tcl. The reasons for this aren't really germane to this answer though.)

Could the problem be as simple as the fact that you don't have "." in your PATH? What if instead of calling your script like "myscript.tcl" you call it like "./myscript.tcl" or "/absolute/path/to/myscript.tcl"?

Related

Is there a way to bundle the bash interpreter along with the script?

I would like to avoid bugs/behaviors from the old versions of the bash interpreter, is there a solution to bundle a recent(like, >4.3) bash interpreter along with the script?
It is a bad idea to write a script used for in a specific version of a shell. Write POSIX compliant shell scripts, it is not that difficult.
However, you can declare what interpreter is needed for the script at the top of your file with a shebang:
#!/path/to/interpreter
A common (and recommended) shebang for shell scripts is:
#!/bin/sh which links to the system shell.
If you want a particular shell, like bash, you would write:
#!/bin/bash
For requiring specific versions of bash, you would need to write a check to verify the version of bash that is present.

What is the Bash file extension?

I have written a bash script in a text editor, what extension do I save my script as so it can run as a bash script? I've created a script that should in theory start an ssh server. I am wondering how to make the script execute once I click on it. I am running OS X 10.9.5.
Disagreeing with the other answers, there's a common convention to use a .sh extension for shell scripts -- but it's not a useful convention. It's better not to use an extension at all. The advantage of being able tell that foo.sh is a shell script because of its name is minimal, and you pay for it with a loss of flexibility.
To make a bash script executable, it needs to have a shebang line at the top:
#!/bin/bash
and use the chmod +x command so that the system recognizes it as an executable file. It then needs to be installed in one of the directories listed in your $PATH. If the script is called foo, you can then execute it from a shell prompt by typing foo. Or if it's in the current directory (common for temporary scripts), you can type ./foo.
Neither the shell nor the operating system pays any attention to the extension part of the file name. It's just part of the name. And by not giving it a special extension, you ensure that anyone (either a user or another script) that uses it doesn't have to care how it was implemented, whether it's a shell script (sh, bash, csh, or whatever), a Perl, Python, or Awk script, or a binary executable. The system is specifically designed so that either an interpreted script or a binary executable can be invoked without knowing or caring how it's implemented.
UNIX-like systems started out with a purely textual command-line interface. GUIs like KDE and Gnome were added later. In a GUI desktop system, you can typically run a program (again, whether it's a script or a binary executable) by, for example, double-clicking on an icon that refers to it. Typically this discards any output the program might print and doesn't let you pass command-line arguments; it's much less flexible than running it from a shell prompt. But for some programs (mostly GUI clients) it can be more convenient.
Shell scripting is best learned from the command line, not from a GUI.
(Some tools do pay attention to file extensions. For example, compilers typically use the extension to determine the language the code is written in: .c for C, .cpp for c++, etc. This convention doesn't apply to executable files.)
Keep in mind that UNIX (and UNIX-like systems) are not Windows. MS Windows generally uses a file's extension to determine how to open/execute it. Binary executables need to have a .exe extension. If you have a UNIX-like shell installed under Windows, you can configure Windows to recognize a .sh extension as a shell script, and use the shell to open it; Windows doesn't have the #! convention.
You don't need any extension (or you could choose an arbitrary one, but .sh is a useful convention).
You should start your script with #!/bin/bash (that first line is understood by execve(2) syscall), and you should make your file executable by chmod u+x. so if your script is in some file $HOME/somedir/somescriptname.sh you need to type once
chmod u+x $HOME/somedir/somescriptname.sh
in a terminal. See chmod(1) for the command and chmod(2) for the syscall.
Unless you are typing the whole file path, you should put that file in some directory mentioned in your PATH (see environ(7) & execvp(3)), which you might set permanently in your ~/.bashrc if your login shell is bash)
BTW, you could write your script in some other language, e.g. in Python by starting it with #!/usr/bin/python, or in Ocaml by starting it with #!/usr/bin/ocaml...
Executing your script by double-clicking (on what? you did not say!) is a desktop environment issue and could be desktop specific (might be different with
Kde, Mate, Gnome, .... or IceWM or RatPoison). Perhaps reading EWMH spec might help you getting a better picture.
Perhaps making your script executable with chmod might make it clickable on your desktop (apparently, Quartz on MacOSX). But then you probably should make it give some visual feedback.
And several computers don't have any desktop, including your own when you access it remotely with ssh.
I don't believe it is a good idea to run your shell script by clicking. You probably want to be able to give arguments to your shell script (and how would you do that by clicking?), and you should care about its output. If you are able to write a shell script, you are able to use an interactive shell in a terminal. That it the best and most natural way to use a script. Good interactive shells (e.g. zsh or fish or perhaps a recent bash) have delicious and configurable autocompletion facilities and you won't have to type a lot (learn to use the tab key of your keyboard). Also, scripts and programs are often parts of composite commands (pipelines, etc...).
PS. I'm using Unix since 1986, and Linux since 1993. I never started my own programs or scripts by clicking. Why should I?
just .sh.
Run the script like this:
./script.sh
EDIT: Like anubhava said, the extension doesn't really matter. But for organisational reasons, it is still recommended to use extensions.
I know this is quite old now but I feel like this adds to what the question was asking for.
If your on a mac and you want to be able to run a script by double clicking it you need to use the .command extension. Also same as before make file executable with chmod -x.
As was noted before, this isn't really that useful tbh.
TL;DR -- If the user (not necessarily the developer) of the script is using a GUI interface, it depends on what file browser they are using. MacOS's Finder will require the .sh extension in order to execute the script. Gnome Nautilus, however, recognizes properly shebanged scripts with or without the .sh extension.
I know it's already been said multiple times the reasons for and against using an extension on bash scripts, but not as much why or why not to use extensions, but I have what I consider to be a good rule of thumb.
If you're the type who hops in and out of bash and using the terminal in general or are developing a tool for someone else who does not use the terminal, put a .sh extension on your bash scripts. That way, users of that script have the option of double-clicking on that file in a GUI file browser to run the script.
If you're the type who primarily does all or most of your work in the terminal, don't bother putting any extension on your bash scripts. They would serve no purpose in the terminal, assuming that you've already set up your ~/.bashrc file to visually differentiate scripts from directories.
Edit:
In the Gnome Nautilus file browser with 4 test files (each with permissions given for the file to be executed) with stupidly simple bash command to open a terminal window (gnome-terminal):
A file with NO extension with #!/bin/bash on the first line.
It worked by double-clicking on the file.
A file with a .sh extension with #!/bin/bash on the first line.
It worked by double-clicking on the file.
A file with NO extension with NO #!/bin/bash on the first line.
It worked by double-clicking on the file...technically, but the GUI gave no indication that it was a shell script. It said it was just a plain text file.
A file with a .sh extension with NO #!/bin/bash on the first line.
It worked by double-clicking on the file.
However, as Keith Thompson, in the comments of this answer, wisely pointed out, relying on the using the .sh extension instead of the bash shebang on the first line of the file (#!/bin/bash) it could cause problems.
Another however, I recall when I was previously using MacOS, that even properly shebanged (is that a word?) bash scripts without a .sh extension could not be run from the GUI on MacOS. I would love for someone to correct me on that in the comments though. If this is true, it would prove that there is a least one file browser out there where the .sh extension matters.

Putting links to scripts in my cygwin bin

I have made a few python scripts, but is there an easier way to run them? I am using cygwin.
python "C:\Users\Desk\Dropbox\scripts\wsort.py" > data11414_unsorted.txt < data11414_sorted.txt
I want something like this (not typing the path name or "python"):
wsort > data11414_unsorted.txt < data11414_sorted.txt
where wsort is a link to my real wsort.py
Add a
Shebang
to the script
#!/bin/python
then invoke like this
wsort.py > data11414_unsorted.txt < data11414_sorted.txt
First, your question has a Windows-style path (backslashes, beginning with C:) rather than a Cygwin path (/cygdrive/c/Users/Desk/Dropbox/scripts/wsort.py). That implies you're not actually using Cygwin, or if you are, you're ignoring a bunch of warnings.
The below assumes you're using Cygwin Bash (which should be what you get if you start Cygwin Terminal from the Start Menu) and Cygwin Python (which you've installed using Cygwin's setup.exe, not a Windows Python installer). If your not, you're making life more difficult for yourself than you need to.
That out the way, there's a bunch of steps you need to take:
First, make the script executable. Use the chmod command for that, from a Cygwin Bash shell:
chmod +x /cygdrive/c/Users/Desk/Dropbox/scripts/wsort.py
Second, tell the system how to execute it. Add the following line to the top of the script:
#!/bin/python
(That's a "shebang". Python sees it as a comment, so doesn't do anything with it, but Cygwin and other Linux-like systems will use that line to see which program to run the script with. In this case, Python.)
Third, make sure your line endings are correct. Cygwin expects Linux line endings and will fail without them. This may not be a problem, but there's no harm in doing this. Run the following command:
dos2unix /cygdrive/c/Users/Desk/Dropbox/scripts/wsort.py
At this point, you'll be able to call the script by specifying the full path to it in Cygwin. You can't yet run it without specifying where the script is explicitly.
The fourth step is making sure the script is "in your path", ie in one of the folders where Cygwin looks for scripts to run. There are lots of ways to do this, but the most sensible is probably to just add your scripts directory to your path. The following command will add your scripts directory to your path whenever you start a new Cygwin session:
echo 'PATH="/cygdrive/c/Users/Desk/Dropbox/scripts:$PATH"' >>~/.bashrc
You will need to restart your Cygwin terminal for that to take effect, however.
At that point, you'll be able to run the script in Cygwin just by typing wsort.py (and thus use it with redirections and so forth as in your question).
Finally, to be able to call it simply as wsort, there's a number of options. The obvious one is just renaming the file. More usefully (and without copying the file or doing anything liable to break with Dropbox syncing things), try creating an alias:
echo 'alias wsort=wsort.py' >>~/.bashrc
Again, you'll need to restart your Cygwin terminal for that to take effect.
Maybe use an alias ?
alias wsort = "Command_Used"

Unable to execute shell script in Cygwin as a KornShell script

I rarely touch shell scripts, we have another department who write them, so I have an understanding of writing them but no experience. However they all appear rather useless with my issue.
I am trying to execute some KornShell (ksh) scripts on a windows based machine using Cygwin- we use these to launch our Oracle WebLogic servers, now it simply will not execute. I used to be able to execute these exact same scripts fine on my old machine.
Now I have narrowed this down to the fact the 'magic number' or whatever it is at the start of the script where it specifies the script interpreter path:
i.e.:
#!/bin/ksh
if I change it to execute as a simple bash it works i.e:
#!/bin/sh
I went through checking the packages installed for cygwin - now the shells I installed are:
mksh MirdBSD KornShell
bash the bourne again shell
zsh z shell
Should I expect to see a ksh.exe in my cygwin/bin directory? there is a system file 'ksh' which I was making an assume somehow associates it with one of the other shell exes, like mksh.exe
I understand my explanation may well be naff. But that being said, any help would be very much appreciated.
Thanks.
I believe the MirBSD korn shell is called mksh. You can verify this and look for the correct path by typing
% which mksh
% which ksh
or if you have no which,
% type -p mksh
% type -p ksh
or if that fails too, check /etc/shells which should list all valid shells on a system:
% grep ksh /etc/shells
You need to put the full path after the #! line. It will probably be /bin/mksh, so your line needs to look like:
#!/bin/mksh
You've probably fixed it by now, but the answer was no, your Cygwin does not (yet) know about ksh.
I solved this problem by launching the cygwin setup in command-line mode with the -P ksh attribute (as described in http://www.ehow.com/how_8611406_install-ksh-cygwin.html).
You can run a ksh using a bat file
C:\cygwin\bin\dos2unix kshfilename.ksh
C:\cygwin\bin\bash kshfilename.ksh
Running a shell script through Cygwin on Windows
Install KornShell (ksh) into Cygwin by the following process:
Download: ksh.2012-08-06.cygwin.i386.gz
Install ksh via Cygwin setup.
Execture Cygwin setup.exe
Choose: Install from Local Directory
Select the ksh.2012-08-06.cygwin.i386.gz as the Local Package Directory.
Complete Cygwin setup.
Restart Cygwin.

Windows/cygwin shebang line

I am using Sphinx quite often. There is one index that calls a stored procedure with one param as input. The param can be any number from 1 to 10 and each returs different results. Since it would make sphinx config quite crowded, even with inheritance. So I thought I will use shebang line at the start of sphinx config file (stored as sphinx.py now). This works great in production enviroment since it runs on Ubuntu. But I want to run it on my local machine as well, but here is the problem called - Windows. Since I have cygwin as well, I tried to run it via cygwin, but it is the same - nothing happens.
I tried to run with both cygwin paths and windows paths, but both get ignored or treated as comments. From what I have read it should be working with cygwin. Could it be that it does not work since I have to call an exe file?
With:
$ ./indexer.exe sphinx.conf
I have tried to run it as perl script, bash script (via cygwin) and it gets ignored either way.
Is there a reliable way to run shebang lines on Windows? Or force cygwin to at least spit an error in my face... Even hacks are good since its just my development machine.
Any help is appreciated
All a shebang line does is tell the unix system() call what interpreter to use. If you specify indexer.exe then you are saying that you want it to use indexer.exe, so that is what it will use.
If you run Indexer.exe, indexer.exe will decide what to do.
Does Indexer.exe understand shebang lines? Or not?
Perl, as a convenience, will read the shebang line, and if it isn't Perl, it will and call the other program for you.
So maybe call Perl instead of Indexer, and it will do the right thing?

Resources