How to ignore the ./ characters in the file location? - bash

I run the following command to get the location of a .sh file and store it in a variable:
startupfile=`find . -name "startup.sh"`
The result of the above is:
./server1/bin/startup.sh
The next step is to run the startup.sh file.
When I try sh $startupfile, it fails to run the server.
Is there a way to ignore the ./ in the location value? Any other way to run the startup.sh script.

You should use:
startupfile=$(find . -name "startup.sh")
OR less preferred in BASH:
startupfile=`find . -name "startup.sh"`
This is called command substitution
UPDATE:: Post question edit:
To avoid running the script with full path you can place path of startup.sh in your PATH variable, so something like this in your ~/.bashrc:
export PATH=$PATH:~/server1/binripts
Then you can run:
startup.sh
From anywhere your home directory.

The ./ is harmless.
You have another problem. Did you change directory between the two commands? Is the "script" not actually a valid script?

The ./ is not the problem, it is simply a (superfluous) path to the current directory: ./file and ././././file are both valid paths to file in the current directory, the number of leading ./'s doesn't make any difference.
Looking at the source of your original question (before it was edited for better formatting), there were single quotes ' around the command: 'sh $startupfile'. If you had those in the actual command as well, that is your problem; the command should be: sh "$startupfile".
Other than that, it's hard to tell what the problem might be. Check that echo "$startupfile" shows the correct path and only the correct path. If it does, does sh ./server1/bin/startup.sh work? If not, what is the error?

To answer your specific questions:
Is there a way to ignore the ./ in the location value?
There are a couple of ways of stripping off leading directory names. The most efficient, though most obscure is:
startupfile=${startupfile##*/}
That removes the longest string on the left ending in '/'. The second way is a little more obvious, but involves creating a child process:
startupfile=$(basename "$startupfile")
Any other way to run the startup.sh script.
Yes, you could use the PATH environment variable, as #anubhava said. The only thing I would add is that you need execute access on the script; chmod u+x "$startupfile".
However, the implication of the name "startupfile" is that it is doing some sort of initialisation, in which case you might need to run it in the same process using the source or .(dot) command:
source "$startupfile"
You might still need the path in the filename, or update PATH.

Related

shell terminal: sh file prefix ./

A beginner unix shell user question:
When I call a sh file in terminal:
Why do I need to prefix it with self folder and slash: ./ ?
What are the alternatives?
That tells the shell that you want to run a program that exists in your current directory. If that directory already exists in PATH - check with :
echo ${PATH}
then you don't need to use it and you can drop the ./ part.
Your script also needs to have the x bit set with chmod and the first line must tell the shell what new shell to spawn, see -
What is the preferred Bash shebang?
There's a very good description of the difference between running sh script.sh and just ./script.sh here.
Hopefully it helps.

open directory with a variable bash shell

I'am reading in a variable that will contain a version of a certain file (Ex.: V1.0.10) by the following command.
read Version
and there is a possibility that that variable contains dots and I remove them by the next command:
New_Version=`echo $Version | sed -e 's/\.//g'`
but if I use this variable later on in the script, nothing changes at this variable, and I just use the cd command:
cd /data/group/$New_Version
or
cd /data/group/"$New_Version"
Then the error: No such file or directory... : line ...: cd:/data/group/V1010.
I double checked, the files exists, the name is correct but he doesn't find or recognize the directory?
What am I doing wrong?
Hope someone can help!
Thanks
UPDATE: The OP says that the problem was a hidden character in his input. This answer does not describe how to solve that problem. Nonetheless, the OP has marked this answer as accepted. See the comments of Charles Duffy for the actual solution to the OP's problem.
Caveat: I am taking everything in your problem description literally, which leads to the answer below. If you provide examples of the strings that will be passed through $Version it would help clarify the issue.
As I understand it you're reading in the full path of a file in your variable with read Version. Now if you say echo $Version you should get /path/to/foo.bar.
I don't think you'd want to cd into the file /path/to/foo.bar. You'll get an error: Not a directory, because it's a file, not a directory.
Now, consider what sed -e /\.//g will do to the pathname.
echo "/path/to/foo.bar" | sed -e '/\.//g'
/path/to/foobar
Does /path/to/foobar actually exist? No, because foo.bar was a file. You'll get an error: No such file or directory, because the foobar directory does not exist.
If I understand what you are trying to do, you are trying to extract the directory that contains the file specified by $Version. The command dirname /path/to/foo.bar will return /path/to. So you want to set New_version=$( dirname "$Version" ), at which point you should be able to cd $New_version.
P.S. Make sure $Version is reading in an absolute path name, not a relative name, so that it's independent of where you run the script from.

Parent directory of a script

So I am a rookie in Linux and I need some help. I have to write a bash script in which I have to use the parent directory of the script to create a file there, wherever the script would be. It should look like this:
If my script it's in "/home/student/", I need to create, using an in-script command another file called txt in /home/. Any ideas please? Thank you.
There's a subtlety if you want to be able to run your script from anywhere.
eg: if your script is in /home/myHome/someDir/someOther, and you want to create a file in /home/myHome/someDir wherever you are when you run your script.
To solve it, you just need to first derive the directory where your script is.
It can be done using:
SCRIPT_DIRECTORY="$(dirname "$0")"
touch "$SCRIPT_DIRECTORY/../myFile.txt"
Edit: Actually it can be even more subtle, if you want to handle symlinks. ie: if the symlink /home/myHome/mySymlink points at your script, and is the one actually being called, then the previous script will consider /home/myHome/ instead of /home/myHome/someDir/someOther
To handle this case you can do
if [ -L "$0" ] && [ -x $(which readlink) ]; then
ACTUAL_SCRIPT_FILE="$(readlink -mn "$0")"
else
ACTUAL_SCRIPT_FILE="$0"
fi
SCRIPT_DIRECTORY="$(dirname "$ACTUAL_SCRIPT_FILE")"
touch "$SCRIPT_DIRECTORY/../myFile.txt"
use .. to point to parent directory. So you could create a file using something like
MY_SCRIPTDIR="$(dirname $0)"
touch ${MY_SCRIPTDIR}/../abc.txt
From your command prompt or within shell script.
Unfortunately, the other answers either give you the current working directory instead of the directory the script is in, or they will not work if either the script or one of the directories along the way is a symbolic link rather than a real directory.
What will work is:
dirname $(readlink -f "$0")
Explanation:
"$0" is the name of the script as you type it in your command line. Quoting is important for the case it contains whitespace.
readlink will resolve any symbolic links along the way
dirname takes just the directory name from script's full path - it's better readable and safer for corner cases than manually looking for slashes etc.
Now, you will get the correct result even in a complex case: if your script is in /tmp and you create a symbolic link to it in /tmp/abc/, and your current directory will be /home and you run /tmp/abc/your-script, it will correctly output /tmp, not /home nor /tmp/abc.

Why does this script work in the current directory but fail when placed in the path?

I wish to replace my failing memory with a very small shell script.
#!/bin/sh
if ! [ –a $1.sav ]; then
mv $1 $1.sav
cp $1.sav $1
fi
nano $1
is intended to save the original version of a script. If the original has been preserved before, it skips the move-and-copy-back (and I use move-and-copy-back to preserve the original timestamp).
This works as intended if, after I make it executable with chmod I launch it from within the directory where I am editing, e.g. with
./safe.sh filename
However, when I move it into /usr/bin and then I try to run it in a different directory (without the leading ./) it fails with:
*-bash: /usr/bin/safe.sh: /bin/sh: bad interpreter: Text file busy*
My question is, when I move this script into the path (verified by echo $PATH) why does it then fail?
D'oh? Inquiring minds want to know how to make this work.
The . command is not normally used to run standalone scripts, and that seems to be what is confusing you. . is more typically used interactively to add new bindings to your environment (e.g. defining shell functions). It is also used to similar effect within scripts (e.g. to load a script "library").
Once you mark the script executable (per the comments on your question), you should be able to run it equally well from the current directory (e.g. ./safe.sh filename) or from wherever it is in the path (e.g. safe.sh filename).
You may want to remove .sh from the name, to fit with the usual conventions of command names.
BTW: I note that you mistakenly capitalize If in the script.
The error bad interpreter: Text file busy occurs if the script is open for write (see this SE question and this SF question). Make sure you don't have it open (e.g. in a editor) when attempting to run it.

Using variables for paths in shell

I want to write a cript for a user to set an installation path.
I am using this
read $file_path
cd $file_path
But it does not change to the path saved on that variable.
How can i set this exactly because this seems the wrong way?
read does not use the $ to read the variable. Hence, it should be
read file_path
cd $file_path
Somewhat reading between the lines, I think you are trying to call a script which you expect to change directory of the caller: For example:
myscript:
read file_path
cd "$file_path"
command-line:
./myscript
and you find it hasn't changed the directory. That's because you are running the script in a child process. It changes the current directory of the child, then returns to the parent, which is unaffected.
You need to source the file instead, that is, run the commands in the current process, not a separate one:
. ./myscript
Yes, notice the extra 'dot' . at the start. This is generically known as the source command, and you can use source instead of 'dot' on bash and csh.

Resources