Cwd::abs_path broken on msys, cygwin - perl

I'm trying to get the absolute path to a file provided as a Windows path in Cygwin, respectively Msys (Git Bash) perl. I would like solutions that also work when the supplied path is a "native" Cygwin/MSys path.
I tried using Cwd::abs_path, but that seems subtly broken. Here is a test:
user#MYPC MINGW64 /f/Temp
$ perl
use Cwd;
print Cwd::abs_path("F:\\") . "\n";
print Cwd::abs_path("F:\\test.txt") . "\n";
print Cwd::abs_path("..\\test.txt") . "\n";
/f
/f/Temp/F:/test.txt
/f/Temp/../test.txt
Directories work, relative paths "work" but don't give the result I'd expect (i.e. .. is not eliminated), but when I add a filename to an absolute path the result is wrong. I had hoped that Cwd would do the path translation for me.
I need to later extract parts of the path (using the functions from File::Spec) and also want open the file. To continue working with the extracted part the path should be native to the perl version used. I want to avoid using cygpath, since I'd like the script to also work with ActivePerl, which understands Windows paths only. I could of course add some ifs to only call cygpath for the unix-y perls.

You do not have an absolute path. msys and cygwin are unix emulation environments, and in unix, absolute paths start with /. F:\ is a valid relative path and file name in unix.
Linux$ touch 'F:\'
Linux$ ls
F:\
In cygwin, /cygdrive/f/ refers to your F:. You can use the command-line utility cygpath to convert between native and Windows paths.
cygwin$ cygpath -w /cygdrive/c/
C:\
cygwin$ cygpath -u 'C:\'
/cygdrive/c/
msys should also have a way of accessing the Windows drive through its virtual unix file system.

Related

FInding relative path in Perl

I have the following code in a perl module,
package Foo;
our $pathToScript = "/home/Lucas/project841/python_script.py";
It is frequently called by other modules in the same file directory through
$output = `$Foo::pathToScript`;
# etc
I would like to remove the hard coding of the actual path and use relative path, Eg. ./python_script.py to call the script from other modules.
What would be the ideal way?
You said your Perl script is "frequently" called from the same directory where the Python script resides, not "always". If you remove the absolute path, you'll need to change that "frequently" to "always", and just change $pathToScript to the Python script name (no path).
You could also consider setting the environment PATH (in the Perl script) so that the Python script (without the full path in $pathToScript) is always found, regardless of where the user is running from or where the Perl script is located.

Getting error while running perl module from command line

I have a customized perl module(Modulehere) that take xls sheet and parsing it.
I tried to run that from commandline itself like:
perl -I /home/suser/modules -e "use Modulehere;Modulehere::load_it('/tmp/test.xls')"
But it gives the error like:
Can't open perl script "–e": No such file or directory
Please help!
It works on my machines (OS X and Linux) but looking at the documentation (man perlrun)
-Idirectory
Directories specified by -I are prepended to the search path for modules (#INC).
There is no space between -I and the directory. Maybe your Perl version is being to strict and considering everything after the space as a script file.

Running a script in bash

I have a script in one of my application folders.Usually I just cd into that locatin in Unix box and run the script e.g.
UNIX> cd My\Folder\
My\Folder> MyScript
This prints the required result.
I am not sure how do I do this in Bash script.I have done the following
#!/bin/bash
mydir=My\Folder\
cd $mydir
echo $(pwd)
This basically puts me in the right folder to run the required script . But I am not sure how to run the script in the code?
If you can call MyScript (as opposed to ./MyScript), obviously the current directory (".") is part of your PATH. (Which, by the way, isn't a good idea.)
That means you can call MyScript in your script just like that:
#!/bin/bash
mydir=My/Folder/
cd $mydir
echo $(pwd)
MyScript
As I said, ./MyScript would be better (not as ambiguous). See Michael Wild's comment about directory separators.
Generally speaking, Bash considers everything that does not resolve to a builtin keyword (like if, while, do etc.) as a call to an executable or script (*) located somewhere in your PATH. It will check each directory in the PATH, in turn, for a so-named executable / script, and execute the first one it finds (which might or might not be the MyScript you are intending to run). That's why specifying that you mean the very MyScript in this directory (./) is the better choice.
(*): Unless, of course, there is a function of that name defined.
#!/bin/bash
mydir=My/Folder/
cd $mydir
echo $(pwd)
MyScript
I would rather put the name in quotes. This makes it easier to read and save against mistakes.
#!/bin/bash
mydir="My Folder"
cd "$mydir"
echo $(pwd)
./MyScript
Your nickname says it all ;-)
When a command is entered at the prompt that doesn't contain a /, Bash first checks whether it is a alias or a function. Then it checks whether it is a built-in command, and only then it starts searching on the PATH. This is a shell variable that contains a list of directories to search for commands. It appears that in your case . (i.e. the current directory) is in the PATH, which is generally considered to be a pretty bad idea.
If the command contains a /, no look-up in the PATH is performed. Instead an exact match is required. If starting with a / it is an absolute path, and the file must exist. Otherwise it is a relative path, and the file must exist relative to the current working directory.
So, you have two acceptable options:
Put your script in some directory that is on your PATH. Alternatively, add the directory containing the script to the PATH variable.
Use an absolute or relative path to invoke your script.

How do we replace PATH in all the files with an env variable

I have around 230 files which are *.pl , *.txt and some are *.conf files which has a default path set to the current environment say /home/AD/USR/perl/5.8.0/bin/perl. I need to replace "/home/AD/USR" with an environment variable ${USR_PATH}. The files I want to modify are in subdirectories. Which means my script should find e.g find .|xargs grep -l "/home/AD/USR" all the files and then replace the string.
OLD: /home/AD/USR/perl/5.8.0/bin/perl
New : ${USR_PATH}/perl/5.8.0/bin/perl
Can some one give me a clue how do I do that?
Shell : /bin/bash
Env : Linux x86_64
If you replace part of a string with ${USR_PATH} you will refer to the perl variable $USR_PATH, not the environment variable, which is in perl referred to as $ENV{USR_PATH}.
perl -pi.bak -we 's#/home/AD/USR(?=/perl/5.8.0/bin/perl)#\$ENV{USR_PATH}#g'
*.pl *.txt *.conf
Using the lookahead will save you the trouble of replacing the rest of the path afterwards.
I assume you want to replace it with the literal value. If you want to replace it with the actual value in the environment variable, just remove the backslash in front of $ENV.
While using an environment variable seems handy and all, it will reduce your scripts portability. Why not use a configuration file? If you had done that from the start, you wouldn't be having this trouble. Search CPAN for a nice module.
perl -i -pe 's|/home/AD/USR/perl/5.8.0/bin/perl|\${USR_PATH}/perl/5.8.0/bin/perl|' <your files>

Perl alternative to Cwd::abs_path for symbolic links

My Perl app receives relative paths to files and arguments and then converts them to absolute paths. I had been using Cwd::abs_path($fileName) just fine, but now I need to support symbolic links and I find that abs_path will give me the absolute path to the original file.
What I need is an alternative to Cwd::abs_path that when given a relative path to a symlink will convert it to an absolute path to that same symlink. Any recommendations?
Example:
/originals/myfile1
/links/myfile1link -> /originals/myfile1
> cd /links
> perl converter.pl /myfile1link
> output: /links/myfile1link
File::Spec->rel2abs does not do any system checks, so it won't resolve symlinks.