CrashBlossom has asked for the wisdom of the Perl Monks concerning the following question:
I am running strawberry perl 5.30 under windows 11.
I am trying to use fsutil to create an 8dot3 name for a directory name which includes unicode characters. The command is:
fsutil file setShortName "C:/Users/James/Music/國語懷 +;念老歌 Vol. 2" "Vol2~00A"
FYI, the characters are Chinese - not displayed correctly here for some reason. Anyway, when I enter the command directly into a command shell, it creates the 8dot3 name as desired. But if I try to run the command in a perl program using backticks, it does not work.
Here is my program:
use strict; use warnings; use utf8; use open ':std', ':encoding(UTF-8)'; use Win32::Unicode; use Win32::Unicode::Dir; use Win32::Unicode::File; use Win32::Unicode::Console; use Win32::Console; Win32::Console::OutputCP(65001); # code page for Unicode (UTF-8) my $cmd = "fsutil file setShortName \"C:/Users/James/Music/國 +5486;懷念老歌 Vol. 2\" \"Vol2~00A\""; my $trans = `$cmd`; print "CMD: $cmd\nTRANS: \"$trans\"";
The output is:
CMD: fsutil file setShortName "C:/Users/James/Music/國語&# +25079;念老歌 Vol. 2" "Vol2~00A" TRANS: "Error: The system cannot find the file specified.
Can anyone help me understand why I an getting this result, and what I can change to fix it?
Thanks
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Problem running shell command from Perl
by atcroft (Abbot) on Jun 20, 2023 at 02:37 UTC | |
Were I to hazard a guess, I would say it is the fact that the Windows CMD prompt does not understand '/' as a path separator; instead, it uses '\' (which most things with a *nix background -- including C and perl -- use as an escape character). In order to include a '\' in a string, you would need to use "\\", or a '\' in a single-quoted string. You can also use the q or qq operators as a way to quote the string. ('q//' is a way to represent a single-quoted string, and 'qq//' a double-quoted string.)
Hope that helps. | [reply] [d/l] |
by CrashBlossom (Beadle) on Jun 20, 2023 at 02:58 UTC | |
Thanks for your response. I did try using "\\" as the separator, and also tried using 'q//' as described in your msg. In both cases I got the same result: "Error: The system cannot find the file specified" | [reply] |
by atcroft (Abbot) on Jun 20, 2023 at 06:46 UTC | |
If memory serves, {value}; is an HTML representation; you might have to designate those characters using the \x{value} or \N{U+value}. So you might try writing that part of the string as something like:
Does that help? | [reply] [d/l] |
by CrashBlossom (Beadle) on Jun 20, 2023 at 17:26 UTC | |
|
Re: Problem running shell command from Perl
by NERDVANA (Priest) on Jun 21, 2023 at 00:44 UTC | |
Unless things have changed (I last checked maybe 7 years ago), Win32 Perl builds are using the Ansi Windows API, rather than the "Wide" windows API that supports Unicode. This affects things like using CreateProcessA instead of CreateProcessW when you call 'system'. I don't know if it is actually possible to specify a unicode filename using CreateProcessA, and in fact this probably means that Perl *requires* the use of those 8.3 filenames that you're trying to detect. What happens if you "readdir" on the directory that file is in? (or any other common perl library for listing the directory) What do you get back? It might be that the only workaround is to use the Win32 module directly. Oh, but now that I look there, I see Win32::GetANSIPathName. I can't imagine that would be useful if it didn't accept unicode filenames, so maybe give that a try? | [reply] |
|
Re: Problem running shell command from Perl
by dasgar (Priest) on Jun 20, 2023 at 18:55 UTC | |
If I'm correctly understanding your posts in this thread, you're basically wanting to get the short path name (i.e. 8.3 format) of a path that contains Unicode characters. And you're wanting to use a system command to get the short path. In Windows, there's two different APIs to the filesystem. The most commonly used API does not support paths with Unicode characters or long paths (limit is around 255 characters). I don't know if the system command that you are trying to use has these limitations or not. Try taking a look at Win32::LongPath, which supports long paths and paths that use Unicode characters. In particular, it provides a shortpathL function to get a short path. This module might provide you with what you need without having to make a system call. You might need to look at harangzsolt33's post about a registry change needed to enable short paths on Windows 11. I don't have a Windows 11 system to test this out - especially the tidbit from harangzsolt33 about enabling short paths in Windows 11. | [reply] |
|
Re: Problem running shell command from Perl
by bliako (Abbot) on Jun 21, 2023 at 07:50 UTC | |
It could be that it is the Windows shell that mangles the parameters of the system command and not Perl (and that answers also your statement: considering what a mess perl's handling of unicode is). It could also be that it is not a unicode issue but a filename/parameters quoting issue which somehow surfaces with unicode filenames in a Windows shell/command-prompt. Ideally, you want to run fsutil without you or Perl opening a Windows shell (command prompt). Further more, system states: When system's arguments are executed indirectly by the shell, results and return codes are subject to its quirks. I would stress the word "quirks". On top of that, shelling out on Windows may impose extra challenges because of lack of Perl implementation for fork in this OS (not Perl's fault, see perlfork). That said, there are quite a few ways to execute a shell command in Perl (backtics, various forms of system(), IPC::run3, possibly others). I would experiment with those before resorting to the batch file solution offered by harangzsolt33 solely because of its roundabout way but, otherwise, it is a good solution which "catches the mouse" so-to-speak. As an example (and noting system()'s documentation AND, particularly, system() Windows issues) here is how to use the system PROGRAM LIST form (not tested and I am ignorant of Windows):
Edit: added q/Vol2~00A/ to script above. bw, bliako | [reply] [d/l] [select] |
by karlgoethebier (Abbot) on Jun 21, 2023 at 10:58 UTC | |
«I don’t know…» It exists. See Features new to Windows XP. «The Crux of the Biscuit is the Apostrophe» | [reply] |
|
Re: Problem running shell command from Perl
by harangzsolt33 (Deacon) on Jun 20, 2023 at 06:13 UTC | |
1) Windows has a registry switch that turns on support for 8+3 short name access on the file system. Short names are not supported by default on NTFS file systems on Windows 11. This means you'll have to tweak your system a little bit... https://guyrleech.wordpress.com/2014/04/15/ntfs-8-3-short-names-solving-the-issues/ 2) The path must be separated by backslash on Windows OS, not forward slashes. If you are using the builtin open() function in Perl, it will accept a path that includes forward slashes, but if you provide that path to a 3rd-party program or command line utility, chances are it won't recognize it as valid and will complain. 3) Why do you use this HTML-style syntax in the command line to quote Chinese characters? When you type &#number; then the terminal will not translate that into a UTF character but will treat it as literal characters. So, it will look for a file that literally contains & # 3 2 7 6 9 ; rather than the Chinese character that you want to quote. 4) The Documents, Music, Pictures, and Downloads folder on Windows are special folders, and the actual name of the directory may be different than what appears in Windows. This has given me much confusion at one time, because I was looking at the same directory tree from Windows and then from Linux, and I saw two different things. From Linux, I saw that each directory name was preceded by the word "My" but looking at it from Windows, I did not see the word "My" in front of each directory. So, if you still get the file not found error, maybe try typing "My Music" rather than just "Music." 5) Sorry, I don't know how to do this in Perl, but I do know how I would do it in JavaScript, so I wrote a Perl script that produces a JavaScript code that renames files... This function is called WinRenameFile() and it has a unique syntax. You may use forward slashes, but it requires that you put the UTF character codes enclosed within { } brackets. So, you would use it like this: WinRenameFile("C:/Users/James/Music/{22283}{35486}{25079}{24565}{32769}{27468} Vol. 2", "|Vol2~00A"); Before you do this, I would double check the directory contents though using the WinReadDir() function as shown below:
Now here comes the downvoting crowd. They have nothing smart to say but downvote every post or comment I make. These people actually ruin Perl's reputation. A programming language is only as good as its community, and sadly Perl's community has become kind of toxic. The goal is no longer to help each other but to bully people. Not very nice. Its kind of a childish behavior... The ones I am writing about know who they are. | [reply] [d/l] |
by marto (Cardinal) on Jun 20, 2023 at 14:03 UTC | |
"They have nothing smart to say but downvote every post or comment I make. These people actually ruin Perl's reputation. A programming language is only as good as its community, and sadly Perl's community has become kind of toxic. The goal is no longer to help each other but to bully people. Not very nice. Its kind of a childish behavior" You get lots of feedback on your posts, you have a tendency to ignore, argue against proven failures or better ways of achieving things. Take a step back and look at your previous comments, recently Re: game programming and the responses you got either outright disproving what you wrote (despite the assertion "everything I have said is the truth."), or commenting on the helpfulness or correctness of your post. Like that thread, here someone (unsurprisingly) is trying to achieve something using perl, you provide some JavaScript. Perhaps you should look objectively at your own behaviour before calling out others. Traits of toxic people | [reply] |
| |
by bliako (Abbot) on Jun 20, 2023 at 07:29 UTC | |
Well, I, for one, have upvoted your post because thanks to it I now know that MS-windows offers the CSCRIPT.EXE command which "Starts a script to run in a command-line environment." (https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/cscript). Just that sentence confirms to me that MS apart from incompetent developers also sports illiterate copy editors. Quite funny is the /nologo flag and that the maximum runtime is 9 hours (see /t:<seconds>) which is very wise since MS OSes need a reboot every couple of hours. Apropos the content of your script, is this OK? $OLD =~ tr|\\||s; # Remove duplicate backslash. . edit:false alarm for $OLD, sorry I missed the /s modifier bw, bliako | [reply] [d/l] [select] |
by Anonymous Monk on Jun 20, 2023 at 11:14 UTC | |
| [reply] |
| |
by CrashBlossom (Beadle) on Jun 20, 2023 at 14:48 UTC | |
Let me give a bit more detail about that I'm trying to do. I have an app that allows the user to browse through directories and select files whose names are then passed to various other applications. Some of these apps can't handle filenames that contain unicode (non 7-bit ascii) characters). I want to modify my app so that if the user selects a file or directory containing unicode characters, my app can create the 8dot3 name on the fly. I can then run the filename through Win32::GetShortPathName to get a name consisting entirely of 7-bit ascii characters. To address the points mentioned in your post: 1. 8dot3 names are already enabled on my system 2. understood 3.The perlmonks website converted the chinese characters to the notation that ended up in the post, apparently due to the fact that the filename was contained in a "<code>" section. Here's the real filename: C:\Users\James\Music\國語懷念老歌 Vol. 2 So if I paste the following into a windows command shell fsutil file setShortName "C:\Users\James\Music\國語懷念老歌 Vol. 2" "Vol~002" the 8dot3 name is created as desired. Now I need to find a way to do this in my perl program. 4. not a problem in my case 5. I need to preserve the original file names, so renaming is not an option.
| [reply] |
by CrashBlossom (Beadle) on Jun 20, 2023 at 15:19 UTC | |
I have discovered that if the original filename does not contain unicode chars (ie all 7-bit ascii), my program can create an 8dot3 name. So the following works: my $trans2 = `fsutil file setShortName \"C:\\Users\\James\\Music\\thewarrior16\" \"THEW~001\"`; But if the filename contains unicode, the fsutil command fails. So the following does NOT work: my $trans = `fsutil file setShortName \"C:\\Users\\James\\Music\\國語懷念老歌 Vol. 2\" \"Vol2~0UG\"`; Is perl somehow mangling the unicode chars before it passes them to fsutil? There's got to be a simple solution to this. But then, considering what a mess perl's handling of unicode is, maybe not ... Any more ideas? | [reply] |
by harangzsolt33 (Deacon) on Jun 20, 2023 at 16:59 UTC | |
by CrashBlossom (Beadle) on Jun 20, 2023 at 18:59 UTC | |
| |