%O parameter doesn't quote filenames with spaces

The behaviour described in the bug report is either by design, or would be far too complex/time-consuming to be changed

Moderators: Hacker, petermad, Stefan2, white

User avatar
petermad
Power Member
Power Member
Posts: 16098
Joined: 2003-02-05, 20:24 UTC
Location: Denmark
Contact:

Re: %O parameter doesn't quote filenames with spaces

Post by *petermad »

2iG0R

I don't know the syntax for your Powershell Script but using: %X%Y%P%S%T%R looks odd to me - how is you script supposed to recognize when the output from %P%S ends and the output from %T%R begins? - Especially in a case where there are no spaces in the paths and the outputs are not auto-quoted - I would think that %X%Y%P%S %T%R would be the way to go. And if the script requires quotes around the entire argument list use %X%Y'%P%S %T%R'

You can always test the resolving of your parameters by putting a ?-mark in front of the parameters - then you can see in the dialog box what TC will pass to the program.

But after testing with ? in the parameters I see this in TC's handling of %X%Y%"P%S %T%R":
- if I mark "my file1.txt" in the left panel and "my file2.txt" in the right panel I get "Left_path\my file1.txt %T%R"
- If I remove the outer quotes and use %X%Y%P%S %T%R I get: "Left_path\my file1.txt" "Right_path\my file2.txt"
- If I use single quotes %X%Y'%P%S %T%R' I get: '"Left_path\my file1.txt" "Right_path\my file2.txt"'

The reason that using double-quotation marks does not work has to do with these features:
history.txt wrote:29.04.21 Added: Parameters %S, %R, %P%S and %T%R now support appended text for each file. The parameter must be in double quotes, e.g. "%P%S.bak" would append .bak to each name (32/64)

09.08.23 Added: Button bar, start menu, parameters field: Better handling of parameters %S, %R, %P%S and %T%R in double quotes with appended text: "%Sbeforeext%Eafterext" inserts string beforeext before extension, and string afterext after. Supports env vars in the form %|variablename| (32/64)
Also the help explicitly says:
Help wrote:%P%S
insert the names of all selected files into the command line, with full path. Names containing spaces will be surrounded by double quotes. Do NOT put quotes around %P%S yourself!
So that is why "P%S %T%R" does not work as you intended, because TC sees %T%R as a text that has to be appended to each filename.
License #524 (1994)
Danish Total Commander Translator
TC 11.55rc4 32+64bit on Win XP 32bit & Win 7, 8.1 & 10 (22H2) 64bit, 'Everything' 1.5.0.1393a
TC 3.60b4 on Android 6, 13, 14
TC Extended Menus | TC Languagebar | TC Dark Help | PHSM-Calendar
iG0R
Junior Member
Junior Member
Posts: 58
Joined: 2018-10-05, 16:16 UTC

Re: %O parameter doesn't quote filenames with spaces

Post by *iG0R »

petermad wrote: 2024-08-17, 08:22 UTC
Thank you so much for such a detailed explanation!

Here is my script:

Code: Select all

#Set-PSDebug -Trace 2

# Print the full command line used to run the script
Write-Host "Script was run with the following command:"
Write-Host $MyInvocation.Line
Write-Host ""

# Function to split the input string based on the pattern "space followed by drive letter and a path"
function Split-ArgumentsByPattern {
    param (
        [string]$inputString
    )

    # Regular expression pattern to match space followed by drive letter and path
    $pattern = '(?<=\s|"|^)([A-Za-z]:\\[^\/\:\*\?\"\<\>\|]+(?= [A-Za-z]:|"|$))'

    # Split the string by the pattern
    $folders = [regex]::Matches($inputString, $pattern) | ForEach-Object { $_.Value }

    # Remove any leading or trailing whitespace from each folder path
    $folders = $folders | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" }

    return $folders
}

# Combine all arguments into a single string
Write-Host "Arguments         : $args"
Write-Host ""
#$combinedArgs = $args -join " "
#Write-Host "Combined Arguments: $combinedArgs"
#Write-Host ""

# Split the combined string into individual folder paths
$rootFolders = Split-ArgumentsByPattern -inputString $args #$combinedArgs

# Print each folder path passed in the array
Write-Host "RootFolders from arguments:"
foreach ($folder in $rootFolders) {
    Write-Host "- $folder"
}

# Function to update the parent folder's LastWriteTime
function Update-ParentFolderTime {
    param (
        [string]$folderPath
    )

    # Get all items (files and subfolders) in the current folder
    $items = Get-ChildItem -Path $folderPath -Recurse

    # Find the item with the most recent LastWriteTime
    $mostRecentItem = $items | Sort-Object LastWriteTime -Descending | Select-Object -First 1

    # If there's a most recent item, compare its LastWriteTime with the parent folder
    if ($mostRecentItem) {
        $parentFolder = Get-Item -Path $folderPath

        if ($parentFolder.LastWriteTime -lt $mostRecentItem.LastWriteTime) {
            # Update the parent folder's LastWriteTime to the most recent item's LastWriteTime
            Write-Host "6. Updating LastWriteTime of the folder '$folderPath' from $($parentFolder.LastWriteTime) to $($mostRecentItem.LastWriteTime)" -ForegroundColor Red
            $parentFolder.LastWriteTime = $mostRecentItem.LastWriteTime            
        } else {
            Write-Host "7. The folder '$folderPath' has the most recent LastWriteTime than its child files and subfolders" -ForegroundColor DarkGreen
        }
    }
}

# Function to recursively process all folders starting from the bottom level
function Process-Folders {
    param (
        [string]$rootFolder
    )

    # Get all subfolders
    $subfolders = Get-ChildItem -Path $rootFolder -Directory
    Write-Host "1. $subfolders = Get-ChildItem -Path $rootFolder -Directory"
    Write-Host "2. $subfolders"

    foreach ($subfolder in $subfolders) {
        # Recursively process subfolders
        Write-Host "3. Process-Folders -rootFolder $($subfolder.FullName)"
        Process-Folders -rootFolder $subfolder.FullName
    }

    # Update the currently processed root folder
    Write-Host "5. Update-ParentFolderTime -folderPath $rootfolder"
    Update-ParentFolderTime -folderPath $rootFolder
}


# Validate that at least one folder is provided as argument
if (-not $rootFolders) {
    Write-Host '
--------------------------------------------------------
Please provide one or more root folder paths as arguments.

For example:
.\UpdateFolderModifiedDate.ps1 "C:\path\to\folder"
or
.\UpdateFolderModifiedDate.ps1 C:\path\to\folder
or
.\UpdateFolderModifiedDate.ps1 "C:\path\to\folder" "C:\path\to\another\folder" "C:\path\to\yet\another\folder"
or
.\UpdateFolderModifiedDate.ps1 C:\path\to\folder C:\path\to\another\folder C:\path\to\yet\another\folder
--------------------------------------------------------

'
    
    # If no arguments were provided, prompt the user to enter one or more folder paths
    $input = Read-Host 'Or please enter the paths of the folders you want to process (without/with quotes, just separate multiple paths with the space/s).

For example:
"C:\path\to\folder" "C:\path\to\another\folder"
C:\path\to\folder C:\path\to\another\folder
'
    
    # If the user provided folder paths, split them into an array
    if ($input) {
        $rootFolders = Split-ArgumentsByPattern -inputString $input # -split ",\s*"  # Split by comma, allowing for optional spaces
        Write-Host "Input: $input"
        Write-Host "RootFolders from input: $rootFolders"
    } else {
        Write-Host "No folder paths provided. Exiting script."
        Set-PSDebug -Trace 0
        exit 1
    }
}

# Loop through each provided folder and process it
foreach ($rootFolder in $rootFolders) {
    if (Test-Path $rootFolder) {
        Write-Host "RootFolders from arguments: $rootFolders"
        Write-Host "Processing folder: $rootFolder"
        Process-Folders -rootFolder $rootFolder
    } else {
        Write-Host "Folder not found: $rootFolder"
    }
}

Set-PSDebug -Trace 0
And the button code:

Code: Select all

TOTALCMD#BAR#DATA
powershell.exe -noexit -ExecutionPolicy Bypass "f:\_Downloads\TotalCommander\PlugIns\UpdateFolderModifiedDate-test2.ps1"
'%X%Y%P%S%T%R'
C:\Program Files (x86)\Total Commander\Wcmicons.dll,51
Change the modification date of folders to match the most recent modification date of their child files or subfolders.


-1
I've already tried all variations (with and without spaces and double or single quotes in different positions) that came to my mind without any success :(
For example:
X%Y%P%S% T%R (i.e. with the space between P%S% and T%R)
When I selected three folders only in the right panel:

Code: Select all

f:\_Downloads\TotalCommander\TweakTC\
f:\_Downloads\TotalCommander\Ultimate File Manager\
f:\_Downloads\TotalCommander\DiskInternals (FileSystemsReader)\
the result is the following:

Code: Select all

FileSystemsReader : The term 'FileSystemsReader' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At line:1 char:206
+ ... nager f:\_Downloads\TotalCommander\DiskInternals (FileSystemsReader)T
+                                                       ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (FileSystemsReader:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
Moreover, if I insert a space between P%S% and T%R, and also enclose all parameters in single quotes to avoid the previous error
'X%Y%P%S% T%R'
I get the following:

Code: Select all

Script was run with the following command:
f:\_Downloads\TotalCommander\PlugIns\UpdateFolderModifiedDate-test2.ps1 ' f:\_Downloads\TotalCommander\TweakTC f:\_Downloads\TotalCommander\Ultimate File Manager f:\_Downloads\TotalCommander\DiskInternals (FileSystemsReader)'
As you can see, there is a space between the single quote and the first selected folder.

And the most interesting thing is, if I add a question mark in front of all the parameters
?%X%Y%P%S%T%R
In the dialog box that appears, I see that TC passes the following line in the parameters:

Code: Select all

f:\_Downloads\TotalCommander\TweakTC "f:\_Downloads\TotalCommander\Ultimate File Manager" "f:\_Downloads\TotalCommander\DiskInternals (FileSystemsReader)"
But the script still throws the following error:

Code: Select all

FileSystemsReader : The term 'FileSystemsReader' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At line:1 char:205
+ ... anager f:\_Downloads\TotalCommander\DiskInternals (FileSystemsReader)
+                                                        ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (FileSystemsReader:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
User avatar
petermad
Power Member
Power Member
Posts: 16098
Joined: 2003-02-05, 20:24 UTC
Location: Denmark
Contact:

Re: %O parameter doesn't quote filenames with spaces

Post by *petermad »

2iG0R
Just a simple question - in all the examples you show, you only seem to select items in one panel - so maybe you could just use %X%Y'%P%S' or %X%Y'%T%R' if you never need to select items in both panels.
License #524 (1994)
Danish Total Commander Translator
TC 11.55rc4 32+64bit on Win XP 32bit & Win 7, 8.1 & 10 (22H2) 64bit, 'Everything' 1.5.0.1393a
TC 3.60b4 on Android 6, 13, 14
TC Extended Menus | TC Languagebar | TC Dark Help | PHSM-Calendar
iG0R
Junior Member
Junior Member
Posts: 58
Joined: 2018-10-05, 16:16 UTC

Re: %O parameter doesn't quote filenames with spaces

Post by *iG0R »

petermad wrote: 2024-08-17, 10:37 UTC
I need it to work in all possible scenarios - with only one or both panels.
Post Reply