As in the above title question, my current working directory contains one directory "a" which contains another directory "b". The correct path to directory "b" is "a\b" (on Windows platform). Assuming that "/" is used as "switch" character I expect function GetFileAttributesA() to give an error for the specified path "a/b". The following documentation says nothing about additional internal path separator conversion.
The question is why GetFileAttributesA() works with unix path separators?
The C++ code is (C++14):
#include <windows.h>
int main()
{
DWORD gfa1 = GetFileAttributesA("a\\b");
DWORD gfa2 = GetFileAttributesA("a/b");
// Both gfa1 and gfa2 are equal to FILE_ATTRIBUTE_DIRECTORY
// I expect the gfa2 to be INVALID_FILE_ATTRIBUTES
return 0;
}
The reason why I would expect function to fail with "a/b" is simple. To simplify I have one function which tells if particular path is a directory for both Linux and Windows system. As long as the function has the same behaviour for slashes and backslashes on Windows I'm forced to add the same behaviour on Linux (separator conversion) or vice-versa (do not allow creating directories with "/" on Windows which is not supported by this function).
Many parts of Windows accept both forward and backward slashes, including nearly all the file API's. Both slashes are reserved characters, and can not appear within a file or directory name.
I am not sure this is detailed in a central place, but for the file API's, the Naming Files, Path, and Namespaces document has this to say:
File I/O functions in the Windows API convert "/" to "\" as part of converting the name to an NT-style name, except when using the "\?\" prefix as detailed in the following sections.
As for:
Assuming that "/" is used as "switch" character
Since on the command line any file or directory path containing a space must be quoted, you can safely split such a path with forward slashes from any switches/parameters on that space character or quotation rules. Similar to how there is no issue with - being in file and directory names, but also used by many programs for command line switches.
Related
when i run a command on windows 10 command line that requires a path as one of its params, it works if the path is NOT inside a quotation, but if a path has a space in it, i need to wrap it inside quotes so that it treats as one single path, but then it complains that the file in that path does not exists.
For example:
C:/PROJECTS/desktopfiles/public/libs/cpdf/win64/cpdf.exe C:/Users/john/Documents/cat.pdf C:/Users/john/Documents/my_dog.pdf -o C:/Users/john/Documents/cat_dog_Merged.pdf
The above works,
the below doesn't (because there is a space in my dog.pdf)
C:/PROJECTS/desktopfiles/public/libs/cpdf/win64/cpdf.exe C:/Users/john/Documents/cat.pdf C:/Users/john/Documents/my dog.pdf -o C:/Users/john/Documents/cat_dog_Merged.pdf
You could try to replace spaces with a question mark. The question mark is a wildcard to match "any single character", which would be a space in your case. Like this: my?dog.pdf. Just make sure that there is no other file matching this pattern. But the system should give you some error message then (which might or might not point to the root of the problem).
Another solution that comes to my mind is a batch file that renames the files in question automatically (replacing spaces with underscores) and renames them back after the pdf merge.
Is there some rule for using \ or /?
For example, both cd c:/ and c:\ works fine. Using mkdir x/y does not work, saying that "syntax is incorrect", but works with mkdir x\y.
Can anyone explain what's the difference?
On Windows the forward slash / is in general for parameters and the backslash \ is the directory separator in file/folder names with absolute or relative paths, see Microsoft documentation Naming Files, Paths, and Namespaces.
The Windows file system kernel functions handle also file/folder paths with / as directory separator by auto-correcting them to \ internally for a better compatibility with Unix/Mac platforms like #include statements in C/C++/C# source code files referencing header files with relative paths using / as directory separator or URLs in HTML files with also using / as separator. That are just two of many examples on where a forward slash is used as separator between strings representing directories on file system.
But a Windows batch file should be written with using only \ as directory separator in file/folder strings.
On Unix/Mac the directory separator is / and - is used for options which is sometimes problematic because of file/folder names can also start with character -.
How argument strings are parsed depends on used compiler and the application/command itself. There are some general rules for each platform, but each programmer of an application can define the argument parsing rules by oneself. So it is always recommended to read the documentation of the application or command to use. On Windows this can be in general done by running the command/application with /? while on Unix/Mac the option to get help is usually -? or -h or --help.
There are many applications ported from Unix to Windows which require parameters being specified on command line with - instead of / like ping.
Without using slashes (/) or backslashes (\), is there any way I can create a file on an external drive using a relative path on windows?
Or, put less confusingly...
Say I have to append whatever I do to the path:
C:\Application Data\blib\
Is there any way I can do something like:
C:\Application Data\blib\<WINDOWS_SORCERY>external:\wherever\file.txt
I've tried inserting delete characters (\x7f) and backspace characters (\x08), and the reserved characters, but nothing doing. And from what I can tell the reserved characters would only be helpful if the file were being created from within a batch script; it's being created in a Java program.
edit: By 'nothing doing' I mean I get an error message; the program doesn't strip those characters out.
Here are many comments on some questions (especially for shell) that say basically one or more of the following:
This will fail on file names that contain spaces, newlines, etc,
This will fail if the file is a symbolic link (or not),
This will fail if the $filaneme is a directory and not regular file,
and so on.
While I understand that every script needs its own testing environment, but
these are some common things for what the script should be immune against.
So, my intention is to write a script what will create some directory hierarchy
with "specially crafted" file names for testing purposes.
The question is: what "special" file names are good for this test?
Currently I have (the script creates files and directories) with:
space in the file name
newline in the file name
file name that starts with one of:
- (like command argument)
# (comment char)
! (command history)
file name that contains one of:
| char (pipe)
() chars
* and ? (wildcards)
file name with unicode characters
all above for the directories
symbolic link to the directory
symbolic link to the file
Any other idea what I shouldn't miss?
What comes to my mind:
quotes in the filename single and double
the $ character at the start
several redirection characters like > < << <<<
the ~ char ($HOME)
the ';' (as command delimiter)
backslash in the filename \
basically, go thru ascii table and test all chars, if you think that you need this :)
Some another comments:
If you want test scripts for the stack-overflow questions, you should create one file with the OP's content (calling as the "basic file")
And the all above "special files" should be symlinks to the above basic file. With this method you can easily modify the content of the files (you need change only one - the basic).
Or, if symlinks not a solution for you use hard-links.
Not directly about special characters in the filenames, but it is good care about:
different case filenames, especially for images like image.jpg image.JPG, same filename only different extension
EDIT: Ideas from the comments:
Very long filenames, lots and lots of files, and very deep directory hierarchies (tripleee)
I need to construct a file path inside a Perl script. Which path separator should I use to allow my script to work on both Windows and Unix?
Keep in mind that Windows needs a drive letter.
You want File::Spec's catpath:
catpath()
Takes volume, directory and file portions and returns an entire path.
Under Unix, $volume is ignored, and directory and file are
concatenated. A '/' is inserted if need be. On other OSes, $volume
is significant.
$full_path = File::Spec->catpath( $volume, $directory, $file );
You want File::Spec. There are specific versions for Unix, Win32, and MacOS as well others.
If you find File::Spec cumbersome, as I do, try Path::Class. It gives you directory and file objects to work with rather than having to call long winded File::Spec class methods on strings.
It sounds like you are using path separator to mean the character between directory/file name components. But just in case you meant the other meaning:
Some things (notably environment variables like MANPATH or PERL5LIB) take a list of file or directory names, separated by a path separator character. Perl's Config module portably supplies such a character as $Config::Config{'path_sep'}.
Q:Which path separator should I use to allow my script to work on both Windows and Unix?
A: /.
Explanation:
Windows can work similarly to Unix with / as path separator.
(Mac OS uses : as a path separator instead of /).
The File::Spec modules can also help.
use File::Spec::Functions;
chdir(updir()); # go up one directory
$file = catfile(curdir(), 'temp', 'file.txt');
# on Unix and Win32, './temp/file.txt'
# on Mac OS, ':temp:file.txt'
# on VMS, '[.temp]file.txt'
Source:
http://www.xav.com/perl/lib/Pod/perlport.html