How to remove trailing backslash from %*

Microsoft Windows
Post Reply
jason404
Posts: 10
Joined: 2022-Oct-16, 4:17 am

How to remove trailing backslash from %*

Post by jason404 »

In cmd.exe `%*` appears to be the equivalent of `$*` in bash.

Because of the program that I use to replace cd....

(which is CD Deluxe - I've been using it on Windows and Linux for more than 13 years and it really should be better known https://github.com/m6z/cd-deluxe)

...doesn't like trailing slashes when the path is within double quotes, which I think clink.exe automatically adds. So I want to remove trailing backslashes on any paths that I pass to CD (or rather `cdd.cmd`, because of CD Deluxe).

From an answer on superuser.com I got this, which removes trailing backslashes from a variable:

Code: Select all

IF %datapath:~-1%==\ SET datapath=%datapath:~0,-1%
Whatever I try, I cannot get it work with `%*` instead of `%datapath%`.

Is there any way I can do this?

Alternatively, I believe adding a trailing dot after the backslash will work too.
jason404
Posts: 10
Joined: 2022-Oct-16, 4:17 am

Re: How to remove trailing backslash from %*

Post by jason404 »

This is the `cdd.cmd` script which is part of the Windows version of CD Deluxe:

Code: Select all

@echo off
set pushd_tmp=%TEMP%\pushd.tmp
set cdd_tmp_cmd=%TEMP%\cdd.tmp.cmd
pushd > %pushd_tmp%
%~dps0_cdd.exe %* < %pushd_tmp% > %cdd_tmp_cmd%
%cdd_tmp_cmd%
This is the version I have made which adds a `%OLDPWD%` variable which I find useful, like bash's `$OLDPWD`:

Code: Select all

@echo off
if '%*'=='' goto :cdd
if '%*'=='-' (
    set OLDPWD=%cd%
    goto :cdd
) else (
    goto :cdd
)
:cdd
set pushd_tmp=%TEMP%\pushd.tmp
set cdd_tmp_cmd=%TEMP%\cdd.tmp.cmd
pushd > %pushd_tmp%
if not errorlevel 1 set OLDPWD=%cd%
%~dps0_cdd.exe %* < %pushd_tmp% > %cdd_tmp_cmd%
%cdd_tmp_cmd%
Everything works fine and I should be happy with this, but it would be nice if I could strip trailing backslashes when the path is surrounded with double quotes, which are added when there is a space in the path.

eg. These work:

Code: Select all

>cd jason/winfiles/bin
cdd: jason\winfiles\bin

>cd "jason/winfiles/bin/"
cdd: jason\winfiles\bin\

>cd "jason/winfiles/bin"
cdd: jason\winfiles\bin
This doesn't work:

Code: Select all

>cd "jason\winfiles\bin\"
Cannot match pattern: 'jason\winfiles\bin" '
User avatar
Simon Sheppard
Posts: 191
Joined: 2021-Jul-10, 7:46 pm
Contact:

Re: How to remove trailing backslash from %*

Post by Simon Sheppard »

jason404 wrote: 2023-Aug-13, 1:52 pm From an answer on superuser.com I got this, which removes trailing backslashes from a variable:

Code: Select all

IF %datapath:~-1%==\ SET datapath=%datapath:~0,-1%
Whatever I try, I cannot get it work with `%*` instead of `%datapath%`.

Is there any way I can do this?

Alternatively, I believe adding a trailing dot after the backslash will work too.
%* and %1, %2.. etc are arguments rather than variables, so you cannot modify them with the SET command.

So just add the argument value to an actual variable:

Code: Select all

SET (datapath=%*)
IF %datapath:~-1%==\ SET datapath=%datapath:~0,-1%
jason404
Posts: 10
Joined: 2022-Oct-16, 4:17 am

Re: How to remove trailing backslash from %*

Post by jason404 »

Thanks. I didn't manage to get it working, but it doesn't matter as it would have only added minor convenience.

However, I've been able to add (seemingly) full emulation of bash's tilde character to represent `%USERPROFILE%` to add to the `%OLDPWD%` variable. which is a much better addition I think.

Code: Select all

@echo off
set dest=%*
if '%dest%'=='' goto :cdd
if '%dest:~0,1%' == '~' set dest=%USERPROFILE%%dest:~1%
set OLDPWD=%cd%
:cdd
set pushd_tmp=%TEMP%\pushd.tmp
set cdd_tmp_cmd=%TEMP%\cdd.tmp.cmd
pushd > %pushd_tmp%
%~dps0_cdd.exe %dest% < %pushd_tmp% > %cdd_tmp_cmd%
set dest=
%cdd_tmp_cmd%
It seems to work fine, at least with clink and it doesn't matter if slashes, backslashes or even a combination of the two are used in the paths.
jason404
Posts: 10
Joined: 2022-Oct-16, 4:17 am

Re: How to remove trailing backslash from %*

Post by jason404 »

Oh, well it's not working as well as I first thought...

If there's a space in the path, this line causes and error:

Code: Select all

if '%dest:~0,1%' == '~' set dest=%USERPROFILE%%dest:~1%
eg.

Code: Select all

>cd "Dir with spaces"
The syntax of the command is incorrect.
So this `if` command is being executed in some way even when there is no tilde at the start of the argument. I think it probably has to do with double quotes that are used when there is a space, as the error also happens when a single word is put in double quotes.
jason404
Posts: 10
Joined: 2022-Oct-16, 4:17 am

Re: How to remove trailing backslash from %*

Post by jason404 »

I think I've fixed it:

Code: Select all

@echo off
set dest=%*
if '%dest%'=='' goto :cdd
if qq%dest:~0,1%%dest:~-1%qq == qq""qq set dest=%dest:~1,-1%
if '%dest:~0,1%' == '~' set dest=%USERPROFILE%%dest:~1%
set dest="%dest%"
set OLDPWD="%cd%"
:cdd
set pushd_tmp=%TEMP%\pushd.tmp
set cdd_tmp_cmd=%TEMP%\cdd.tmp.cmd
pushd > %pushd_tmp%
%~dps0_cdd.exe %dest% < %pushd_tmp% > %cdd_tmp_cmd%
set dest=
%cdd_tmp_cmd%
jason404
Posts: 10
Joined: 2022-Oct-16, 4:17 am

Re: How to remove trailing backslash from %*

Post by jason404 »

In case anybody is reading this, I have found that it's probably a bad idea to do this, as...

1. clink seems to be able to be set to expand ~ to %USERPROFILE%, but I'm not sure if it still works

2. It would be better to use clink's ability to do that so that it works with other commands like mv, cp, rm, etc.

3. ...because without general shell support if you use ~ in a path for another command you can just end up renaming the file to ~ instead of copying it moving it etc.
User avatar
Simon Sheppard
Posts: 191
Joined: 2021-Jul-10, 7:46 pm
Contact:

Re: How to remove trailing backslash from %*

Post by Simon Sheppard »

The IF command can seem flaky if any spaces exist in the comparison strings.

for example these 3 commands all seem to work OK

Code: Select all

IF '~a'=='~ a' Echo OK
IF [~a]==[~ a] Echo OK
IF "~a"=="~ a" Echo OK
But if you reverse the logic to see if they are not equal

Code: Select all

IF '~a' NEQ '~ a' Echo OK
IF [~a] NEQ [~ a] Echo OK
IF "~a" NEQ "~ a" Echo OK
IF NOT "~a" == "~ a" 
The first 2 of those will fail and the last 2 will work.

Similarly this will fail:

Code: Select all

IF 'a b'=='a b' Echo OK
Single quotes have no special meaning to CMD, so when it reaches a space it assumes that's the end of the string.
So then you think, OK I'll just use double quotes.
However there is one remaining gotcha, if the item you are comparing is a quoted filename, so it already contains double quotes, you have an escape sequence:

Code: Select all

IF ""long filename"" EQU "something" Echo OK
That will break because the "" acts as an escape. To prevent that from happening strip any quotes from the strings being compared.

I should add something about this to the IF page
https://ss64.com/nt/if.html
Post Reply