softlinking and awk scripts (path issue) - bash

I have main.sh and external.awk files.
They are in the same directory.
From main.sh I am calling that external awk script like this:
awk -f external.awk ..
and of course it is working.
Now when I do:
cd /usr/local/bin
sudo ln -s /path/to/scripts/dir/main.sh main.sh
sudo ln -s /path/to/scripts/dir/external.awk external.awk
I can call my main.sh from whatever directory I am in.
But it gives me error on not being able to find external.awk script.
Why linking does not work in this case, shouldn't that
awk -f external.awk ..
call external.awk relative to folder where it is, thus in this case calling
that symbolic link which is in /usr/local/bin path?
EDIT
Soon after posting my question, I found this as a good way to handle this situation:
https://www.gnu.org/software/gawk/manual/html_node/AWKPATH-Variable.html
It is not POSIX compliant, but in this case it is not of an importance to me.

Modify main.sh to call awk as this:
awk -f /usr/local/bin/external.awk ..

Related

Get Directory Bash Script is Called From if it's a Sym Link

Let's say I have a bash script called program stored in /home/user/program. But then I create a sym link to the bash script using ln -s /home/user/program /usr/bin/program. Then I cd /usr/home/anotherdirectory and then run program. How do I get the bash script to print /usr/home/anotherdirectory to tell me where it was called from?
I tried echo $PWD and it only printed out /usr/bin
This should do the job in your script:
dirname $(readlink -e "$0")
From man readlink:
-e:canonicalize by following every symlink in every component of the given name recursively, all components must exist

shell print effective directory - strip dots

I'm seeking for a shell builtin or a shell command that "calculates" the effective directory path when a path looks like
TOMCAT_HOME=/var/lib/tomcat7/webapps/ROOT/WEB-INF/../..
Result is obviously
/var/lib/tomcat7
I did a
pushd dirname $0
cd ${TOMCAT_HOME}
pwd
popd
which gives me what I want but there must be an easier way, I can't think of it right now
One of the utilities that does that is realpath
$ realpath /var/lib/gconf/defaults/../..
/var/lib
You may need to install it. On Debian, apt-get install realpath.
Another one, part of coreutils, is readlink when used with the -f option:
$ readlink -f /var/lib/gconf/defaults/../..
/var/lib

Get `dirname $0` of a KornShell script called by a symbolic link

I have a folder organization that looks like this:
link.sh
dist/MyApp-3.0.0/script.sh
dist/MyApp-3.0.0/lib/*.jar
The link.sh is a symbolic link to the KornShell (ksh) script script.sh. In the shell script, I want to call a Java program with following command:
java -cp lib/*
When I try to launch the application from the symbolic link, I get ClassNotFound because the relative path is resolved from the link base dir (this is normal).
Inside the shell script, how can I get the full path of the script (<...>/dist/MyApp-3.0.0/)? It will allow me to modify my Java call:
java -cp ${SCRIPT_DIR}/lib/*
Edit: using readlink
You can use readlink, and it boils down to:
SCRIPT_DIR=$(dirname "$(readlink -f $0)")
Edit: without readlink
if test -h $0; then
symdir=$(dirname "$(ls -l $0 | sed -n 's/.*-> //p')")
if [[ -z $symdir ]]; then
symdir=.
fi
fullreldir=$(dirname $0)/$symdir
fi
script_dir=$(cd $fullreldir; /bin/pwd)
I misunderstood the location of the script, and had assumed that the directory of the script being invoked was in the directory structure of the target application, where the following would work:
SCRIPT_DIR=$(cd $(dirname $0); /bin/pwd)
You have to use the readlink function (man readlink)
my2c

Space in directory name creating problem

I am trying to build some code and the location where the compiler is present has a space in it 'blahblah/Source Code/blahblah' .I am not sure how to add this to the environment variable.I use bash and tried to use the normal
export PATH="$PATH:/blahblah/Source Code/blahblah"
but it doesnt seem to work(I also tried using \before spaces).Throws me errors like No such file or directory.Am I missing out on something?
I just did a little experimentation on my own:
$ mkdir 'Source Code'
$ cd Source\ Code/
$ vim testme.pl
$ chmod 755 testme.pl
$ cat testme.pl
#! /usr/bin/perl
print "I worked\n";
$ ./testme.pl
I worked
$ cd ..
$ export PATH="$PATH:/home/bchittenden/Source Code"
$ testme.pl
I worked
This indicates that the problem is not the whitespace in $PATH... bash seems to handle that correctly... you'll have to give us more information.

mdfind used for creating symlinks not working as expected

I am trying to use the output from mdfind to create a bunch of symlinks. Output of mdfind is like this:
/pathtofile1/
/pathtofile2/
/pathtofile3/
So, I used sed to add ln -s to the start of each line, and awk {print $0 "/directory where I want this/"};
after my single-line script successfully outputs this:
ln -s "/pathtofile1/" "/directory where I want this"
ln -s "/pathtofile2/" "/directory where I want this"
ln -s "/pathtofile3/" "/directory where I want this"
Problem is, when I run this, I get this error: "/directory where I want this: File does not exist"
The weird thing is that when I run these lines individually, they links are created as expected, but running the entire command returns the error above.
Any ideas?
I don't think that this is the ideal way to do what I'm trying to do, so let me know if you have any better solutions.
Edited with more information.
#! /bin/bash
itemList=`mdfind -s "$1"| awk '{ print "ln -s \""$0"\" \"/Users/username/Local/Recent\""}'`
echo "$itemList"
`$itemList`
$1 is a test *.savedSearch that returns a list of files.
My result (from the echo) is:
ln -s "/Users/username/Dropbox/Document.pdf" "/Users/username/Local/Recent"
ln -s "/Users/username/Dropbox/Document2.pdf" "/Users/username/Local/Recent"
and the error that I get is:
ln: "/Users/username/Local/Recent": No such file or directory
But, if I run a copy-pasted of each line individually, the links are created as expected.
One way to keep it simple:
mdfind -0 "query" | ( cd "/Users/username/Local/Recent" ; xargs -0 -I path ln -s path . )
This is of course doesn't handle duplicate file names, etc.
EDIT:
The reasons your solution is failing is that, first, the contents of $itemList is being executed as one long command (i.e. the line feeds output by awk are ignored), and then, second, the command substitution occurs before quote removal. What is actually processed is roughly equivalent to:
ln '-s' '"/pathtofile1/"' '"/to"' 'ln' '-s' '"/pathtofile2/"' '"/to"' 'ln' '-s' '"/pathtofile3/"' '"/to"'
/bin/ln recognizes this as the:
ln [-Ffhinsv] source_file ... target_dir
form of the command and checks to see that the final parameter is an existing directory. That test fails because the directory name includes the surrounding quote marks. Note carefully the error message you report and compare:
$ ln a b c "/Users/username/Local/Recent"
ln: /Users/username/Local/Recent: No such file or directory
$ ln a b c '"/Users/username/Local/Recent"'
ln: "/Users/username/Local/Recent": No such file or directory
So the morals of the story are, when you are dealing with file names in a shell, the safest solution is to avoid shell processing of the file names so you don't have to deal with quoting and other side effects (which is a big advantage of an xargs solution) and keep it simple: avoid constructing complex multi-line shell commands. It's too easy to get unexpected results.
It would be much easier to determine what the problem was if you used some actual, or at least plausible, paths as examples, but ln isn't going to create these directories for you if that's what you want.

Resources