File::Spec->catpath does not work for Windows - windows

I am using the File::Spec module like this
my $volume = 'C';
my $path = File::Spec->catpath(
$volume,
File::Spec->catdir('panel', 'texts'),
'file'
);
print $path;
output
Cpanel\texts\file
How is File::Spec a portable module, as discussed in How can I construct OS-independent file paths in Perl ...? if I have to write the volume as C:\ and not just C to get it right?

You have 2 problems. The first is that Windows volume names include the colon, so you should have said $volume = 'C:'. The second is that you specified a relative path, so you got a relative path. If you want an absolute path, you have to give one:
use 5.010;
use File::Spec;
my $volume = 'C:';
my $path = File::Spec->catpath($volume,
File::Spec->catdir('', 'panel', 'texts'), 'file');
say $path;
On Windows, that will print C:\panel\texts\file, and on Unix it will say /panel/texts/file.
Note that it's perfectly legitimate to have a relative path with a volume name on Windows:
File::Spec->catpath('C:',
File::Spec->catdir('panel', 'texts'), 'file');
will give you C:panel/texts/file, which means panel/texts/file relative to the current directory on drive C:. (In Windows, each drive has its own current directory.)

Related

How do we get a drive by its label in PowerShell 5.0?

I have an autorun.inf file with the following contents on my external hard drive:
[Autorun]
Label=MasterSword
This labels my external hard drive once it's plugged in as, MasterSword. I want to store a few scripts on it and include them in my $profile so they are loaded when PowerShell starts or when the profile is re-included (. $profile) at the interpreter.
As many know, using a hard-coded drive letter for external drives can lead to changing the reference to those external hard drive scripts every time the drive letter changes, resulting in the inclusion failing.
So I guess I have two questions:
How do I get a hold of the drive label that was set in the autorun.inf?
How do I translate that drive label into the drive letter so I can reference the scripts stored on it?
I did a little more research and came up with this little snippet:
To answer #1:
$scriptDrive = Get-Volume -FileSystemLabel MasterSword
To answer #2:
$scriptDriveLetter = $scriptDrive.DriveLetter
And together, they would be:
$scriptDrive = Get-Volume -FileSystemLabel MasterSword
$scriptDriveLetter = $scriptDrive.DriveLetter
Or for another interpretation:
$scriptDriveLetter = (Get-Volume -FileSystemLabel MasterSword).DriveLetter
Where the necessary drive letter is stored in $scriptDriveLetter.
You could try:
Get-PSDrive | Where-Object {$_.Description -eq "MasterSword"}
This will return an object such as:
Name : E
Description : MasterSword
Provider : Microsoft.PowerShell.Core\FileSystem
Root : E:\
CurrentLocation : Scripts
Thus, assuming your scripts are in the "Scripts" folder, you can find them with:
$Root = (Get-PSDrive | Where-Object {$_.Description -eq "MasterSword"}).Root
$Path = Join-Path $Root "Scripts"
Here's a modification to ExcellentSP's answer that I used for my own use.
I have the script look for the plugged in usb by name and change the drive letter to a pre-determined drive letter:
$scriptDrive = Get-Volume -FileSystemLabel "mastersword"
Get-Partition -DriveLetter ($scriptDrive.DriveLetter) | Set-Partition -NewDriveLetter W
You can replace -DriveLetter with -DriveNumber as well dependent on your use.
But this was only because I was being lazy and didn't want to do much modifying my old script.
Most likely, the best way to do it is:
$scriptDrive = Get-Volume -FileSystemLabel "mastersword"
$drive = $scriptDrive.DriveLetter
You would then use $drive for any pathways or directories within this drive.
ex: $drive:\folder\picture.jpg

Perl: Check if string is valid directory, case SENSITIVE

So I have run into an issue. The -d switch will check if a directory exists just fine. However, I need it to be case sensitive. If I have directory Users, and I do if -d "UsErS", it will return true. I need it to only return true if the case matches.
Any help is much appreciated.
Code:
if (-d $cmdLine[1]) {
chdir $cmdLine[1];
print "CD: Successfully changed directory.\n";
} else {
print "CD: Error: $cmdLine[1] is not a valid directory.\n";
}
The only definitive source for the file name is the filesystem itself. This snippet lists the entries in the parent of the target directory and verifies that the name specified matches exactly with one of those entries. I tested in from Linux on a remote NTFS share (mounted with CIFS).
use File::Basename;
$target = shift;
($base,$parent) = fileparse($target);
opendir($PARENT,$parent)
or die("Error opening '$parent': $!");
%entries = map { $_ => 1 } readdir($PARENT);
closedir($PARENT);
if (-d $target && exists($entries{$base})) {
print("'$target' exists (and correct case)\n");
} else {
print("'$target' does not exist.\n");
}
I can't conceive of how you could experience this problem outside of a case-insensitive filesystem (e.g. NTFS, (V)FAT, others?), and the problem with them (at least when Windows is the OS managing it) is that you cannot necessarily guarantee that the case of the filesystem entry is what you want it to be. For example, try to rename an NTFS file changing only the case. In Windows, the file name doesn't get changed. You'd have to change it to something different entirely, then change it back to the old name with the correct case. There are (or were) configurable Windows settings that do special things if the file name is all uppercase.
Another thing to consider is that if the filesystem is case-insensitive, then there's no possibility that there could be two entries in the same directory that differed only by case. I just don't understand what useful contingency this check would account for.
Check Win32 module,
use Win32;
if (-d $cmdLine[1] and $cmdLine[1] eq Win32::GetLongPathName($cmdLine[1])) { .. }
You may also need use File::Spec::Functions 'canonpath'; if you want to normalize directory separators (/ into \ on win32)
What TLP is suggesting is to combine both -d and eq. Something like:
if (-d $dirname && $dirname eq "Users"){
....
}
BTW -d alone is working fine for me. It's case sensitive. Try the below code and modify $dir to any directory which exists in your system.
#!/usr/bin/perl
use strict;
use warnings;
my $dir = "/pathto/code";
if(-d $dir){print "DIR: $dir";}
else{print "$dir is not a directory";}

How to print filename/current directory as a title in octave plot from bash?

I am new to octave and need to plot a 2-D graph with customized title either as a file name or current directory name. I tried passing pwd in the plot.m file but it gives me a complete path instead of directory name only. Actually all I need is a customized title without manually hard coding the string inside xlabel('strings').
I don't have Octave but this works on MATLAB:
current_directory_name = pwd;
current_directory_split = regexp(current_directory_name,'/','split');
string_of_interest = current_directory_split(end);
xlabel(string_of_interest);
I am assuming you are on *NIX computer. For Windows computer, change / to \ in the split command.
If I understood your question correctly, you want a portable way of retrieving the file name w/o the directory name. Use fileparts():
[dir, name, ext, ver] = fileparts(pwd)
If you later decide to join strings, use filesep which is portable no matter if you're on Unix or not.

Current path in PHP on Windows (standalone CLI)

I was trying to get path current path in PHP. I tried looking though phpinfo();, but I haven't found any interesting values which could be used to get path to my script. There is no nice values which I used on Linux, like $_SERVER["PWD"].
Now I'm wondering how I'm supposed to find current path. Maybe some function will work... I really have no idea. Because I don't want to hardcode path to script.
getcwd() is what you are looking for.
It's not entirely clear whether you mean the current working directory, or the path to the current script. For the working directory, see #Taze's answer.
For the current script, the __FILE__ magic constant will give you the full filesystem path to the current file.
Note that these constants take "current file" literally: If you include a file and call __FILE__ there, it will show the included file's path.
The getcwd() method will return the current working directory on success.
<?php
echo getcwd() . "\n";
?>

How can I specify the name of a mounted drive in Windows when mounting programmatically?

I am writing a perl routine that mounts specific drives at startup. However, when the drives are mounted, they appear in "My Computer" with odd names like "dir$ at 'machinename' (H:)".
Is there a way in perl or C to specify this string (or just the 'dir$' part?) at mount-time?
You question is not entirely clear to me, but do you mean something like File::Spec's splitpath method?
splitpath
Splits a path in to volume, directory,
and filename portions. On systems with
no concept of volume, returns '' for
volume.
($volume,$directories,$file) = File::Spec->splitpath( $path );
($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file
);
For systems with no syntax
differentiating filenames from
directories, assumes that the last
file is a path unless $no_file is true
or a trailing separator or /. or /..
is present. On Unix, this means that
$no_file true makes this return ( '',
$path, '' ).
The directory portion may or may not
be returned with a trailing '/'.
The results can be passed to catpath()
to get back a path equivalent to
(usually identical to) the original
path.
After much searching, one way to do it is by monkeying with the registry--not a great method, but it works
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\DriveIcons\D\DefaultLabel]
will set the visible label for the D: drive, etc.

Resources