Get last command line argument in windows batch file - windows

I need to get last argument passed to windows batch script, how can I do that?

This will get the count of arguments:
set count=0
for %%a in (%*) do set /a count+=1
To get the actual last argument, you can do
for %%a in (%*) do set last=%%a
Note that this will fail if the command line has unbalanced quotes - the command line is re-parsed by for rather than directly using the parsing used for %1 etc.

The easiest and perhaps most reliable way would be to just use cmd's own parsing for arguments and shift then until no more are there.
Since this destroys the use of %1, etc. you can do it in a subroutine:
#echo off
call :lastarg %*
echo Last argument: %LAST_ARG%
goto :eof
:lastarg
set "LAST_ARG=%~1"
shift
if not "%~1"=="" goto lastarg
goto :eof

An enhanced version of joey's answer:
#ECHO OFF
SETLOCAL
:test
:: https://stackoverflow.com/a/5807218/7485823
CALL :lastarg xxx %*
ECHO Last argument: [%XXX%]
CALL :skiplastarg yyy %*
ECHO skip Last argument: [%yyy%]
GOTO :EOF
:: Return all but last arg in variable given in %1
:skiplastarg returnvar args ...
SETLOCAL
SET $return=%1
SET SKIP_LAST_ARG=
SHIFT
:skiplastarg_2
IF NOT "%~2"=="" SET "SKIP_LAST_ARG=%SKIP_LAST_ARG% %1"
SHIFT
IF NOT "%~1"=="" GOTO skiplastarg_2
ENDLOCAL&CALL SET "%$return%=%SKIP_LAST_ARG:~1%"
GOTO :EOF
:: Return last arg in variable given in %1
:lastarg returnvar args ...
SETLOCAL
SET $return=%1
SET LAST_ARG=
SHIFT
:LASTARG_2
SET "LAST_ARG=%1"
SHIFT
IF NOT "%~1"=="" GOTO lastarg_2
ENDLOCAL&call SET %$return%=%LAST_ARG%
GOTO :EOF
Run it with the arguments:
abe "ba na na" "cir cle"
and get:
Last argument: ["cir cle"]
skip Last argument: [abe "ba na na"]

set first=""
set last=""
for %%a in (%*) do (
SETLOCAL ENABLEDELAYEDEXPANSION
if !first!=="" (set first=!last!) else (set first=!first! !last!)
set last=%%a
)
ENDLOCAL & set "last=%last%" & set "first=%first%"
echo %last% "and" %first%

Related

Windows batch replace last found substring

I faced with problem using windows cmd. I need found and replace last found substring. For instance I have a string - #192.168.0.1:1521:SID. I need to replace the last colon with a slash and recieve #192.168.0.1:1521/SID.
How can I do this?
It looks like you have a fairly well defined format: IPAddress:Number:SID, so this could be treated as replacing the 2nd : with a /
#echo off
set val=#192.168.0.1:1521:SID
for /f "tokens=1,2,* delims=:" %%a in ("%val%") do set newval=%%a:%%b/%%c
echo %newval%
yourcommand %newval%
You can optimize if the format is always the same (e.g. always the 4th char from the end) but as a general solution I would code it like below.
set result=
set left=
set right=#192.168.0.1:1521:SID
:loop
call :sub1 "%right%"
if %result% equ 1 goto :loop
#echo %left%/%right%
goto :eof
:sub1
for /f "delims=: tokens=1*" %%i in ("%~1") do (
if ["%%j"]==[""] (
set /a result=0
goto :eof
)
if ["%left%"]==[""] (
set left=%%i
) else (
set left=%left%:%%i
)
set /a result=1
set right=%%j
)
goto :eof
Explanation:
The code in sub1 splits the argument on the first colon from the left unless there is no colon in the argument - in this case it sets the result to 0 and returns.
The left part is added to the left-variabel, the right part is set to the right-variable.
The main loop calls the sub sub1 until there is no more split and you're done.

windows 7 remaining batch file arguments

In windows batch files, I know %1 is replaced with the first argument, %2 is replaced with the 2nd argument and %* is replaced with all arguments.
Is there a way to get all the arguments after the 1st one? (e.g. arguments 2-N) What about all the arguments after the 2nd one?
The SHIFT command doesn't seem to affect %*.
#ECHO OFF
SETLOCAL
CALL :allafter 3 %*
ECHO args=%args%
GOTO :eof
:allafter
FOR /l %%a IN (1,1,%1) DO SHIFT
(SET args=)
:argloop
shift
IF NOT .%1==. SET args=%args% %1&GOTO argloop
IF DEFINED args SET args=%args:~1%
GOTO :eof
to get everything after the 3rd argument to ARGS
Edit - to take care of space-separated elements which may include commas
#ECHO OFF
SETLOCAL
CALL :allafter 3 %*
ECHO args=%args%
CALL :allafter2 3 %*
ECHO args=%args%
GOTO :eof
:allafter
FOR /l %%a IN (1,1,%1) DO SHIFT
(SET args=)
:argloop
shift
IF NOT .%1==. SET args=%args% %~1&GOTO argloop
IF DEFINED args SET args=%args:~1%
GOTO :EOF
:allafter2
SET /a count=%1
SET args=%*
:arg2loop
SET oldargs=%args%
call SET args=%%args:*%1 =%%
IF "%args%"=="%oldargs%" (call SET args=%%args:*%1,=%%) ELSE (SET /a count-=1)
shift
IF %count% gtr -1 GOTO arg2loop
GOTO :EOF
Hmm- spoke too soon. This modified routine should play nicer. The previous version treated what was to be defined as one argument one,two,three as three separate arguments when the remove-leading-n was invoked.
Well, there is a way-ish...
By using the /n switch on the shift command, you can sort of do something like it. However, it will delete all of the argument and put them into a certain variable (so you can't call %3 anymore without a for loop).
#setlocal enableextensions
#echo off
:loop
if "%~2" equ "" goto end
set variable=%variable% %~2
shift /2
goto loop
:end
echo %1
echo %variable%
endlocal
To separate the parameters again just do a simple for loop (I'm sure you can find documentation on it somewhere).
Solution without shift & goto:
#echo off &setlocal enabledelayedexpansion
set /a count=0
for %%i in (%*) do set /a count+=1
set "args="
for /l %%i in (2,1,%count%) do if defined args (call set "args=!args! %%%%i") else call set "args=%%%%i"
echo.%args%
endlocal
> type t.bat
#echo off
echo %*
for /f "tokens=1,*delims= " %%i in ("%*") do echo %%j
> t a b c d e f,g h i
a b c d e f,g h i
b c d e f,g h i
> t a,a b c d e f,g h i
a,a b c d e f,g h i
b c d e f,g h i
>

Echo length of a variable from the windows command line

So I'm looking for a quick command to evaluate the length of environment variables on the windows command line.
Conceptually, something to the effect of:
echo %PATH%.length
Thanks!
#echo off
setlocal enabledelayedexpansion
call :COUNT "%path%"
echo Your variable is %length% characters long
pause >nul
:COUNT
set temp=%1
set length=0
:loop
if defined temp (
set temp=!temp:~1!
set /a length+=1
goto :loop
)
Usage: call :COUNT %yourvar% and the length will be stored in %length%.

How do I return a value from a function in a batch file?

I have the following batch file
#echo off
setlocal EnableDelayedExpansion
for /f "delims==" %%J in (File_List.txt) do (
call :setDate %%J MYD
echo/Date is: %MYD%
)
endlocal &goto :eof
:setDate
SETLOCAL ENABLEEXTENSIONS
echo %1
echo %~2
set NAME=%1
set NAME=%NAME:~-11%
echo %NAME%
echo %~2
endlocal&set %2=%NAME%&goto :eof
but with File_List.txt containing
file2012-05.csv
I get
file2012-05.csv
MYD
2012-05.csv
MYD
Date is:
How do I actually get the function setDate to return the value I want?
As I don't understand from your script what you want to achieve, I reply (for completeness) to the original subject: returning a value from a function.
Here is how I do it:
#echo off
set myvar=
echo %myvar%
call :myfunction myvar
echo %myvar%
goto :eof
:myfunction
set %1=filled
goto :eof
Result is:
empty
filled
The batch interpreter evaluates %MYD% at parse time, and at that time it's empty. That's why you have Delayed Expansion. Change this line:
echo/Date is: %MYD%
to this:
echo/Date is: !MYD!
and it will work like you want, because then it tells the interpreter to evaluate MYD at run-time.

How do I display integers in hexadecimal, from a batch file?

echo The error level is: %ERRORLEVEL%
Produces
>The error level is: 15
What I would like:
>The error level is: F
do I need to do conversions or is there a way to display numbers differently?
Any help in the right direction is appreciated, thanks.
It was a long time ago, I was very bored.
cmdcalc.cmd
#echo off
if not defined trace set trace=rem
%trace% on
SetLocal
if "%1"=="/?" (
call :help %0
goto :eof
)
Set MinInBase=
if /i "%2" EQU "Bin" call :DoBin %1
if /i "%2" EQU "Hex" call :DoHex %1
If not defined BinStr call :DoDec %1
EndLocal & set RET=%RET%
goto :eof
:DoBin
Set MinInBase=2
Set ShiftBy=1
Set StartSyn=0b
call :DoCalc %1
goto :eof
:DoHex
Set MinInBase=16
Set ShiftBy=4
Set StartSyn=0x
call :DoCalc %1
goto :eof
:DoDec
if {%1} EQU {} goto :eof
set /a BinStr=%1
set RET=%BinStr%
echo %RET%
goto :eof
:DoCalc
Set BinStr=
SET /A A=%1
%Trace% %A%
:StartSplit
SET /A B="A>>%ShiftBy%"
%Trace% %B%
SET /A C="B<<%ShiftBy%"
%Trace% %C%
SET /A C=A-C
%Trace% %C%
call :StringIt %C%
If %B% LSS %MinInBase% goto :EndSplit
set A=%B%
goto :StartSplit
:EndSplit
call :StringIt %B%
set RET=%StartSyn%%BinStr%
Echo %RET%
EndLocal & set RET=%RET%
goto :eof
:StringIt
set Bin=0123456789ABCDEF
FOR /F "tokens=*" %%A in ('echo "%%BIN:~%1,1%%"') do set RET=%%A
set ret=%ret:"=%
Set BinStr=%Ret%%BinStr%
goto :eof
:help
echo %1 syntax:
echo.
echo %1 Calculation [Hex^|Bin]
echo.
echo eg %1 12*2 Hex
echo.
echo gives 0x18.
goto :eof
According to the external resource Windows Environment Variables, there is an undocumented built-in read-only variable =ExitCode which returns the current exit code in hexadecimal format. To ensure the ErrorLevel value equals the exit code, use cmd /C exit %ErrorLevel%.
So if you are using this line code...:
cmd /C exit %ErrorLevel%
echo The error level is: %=ExitCode%
...you will receive this (supposing the ErrorLevel is 15):
The error level is: 0000000F
To get rid of the leading zeros, use this...:
cmd /C exit %ErrorLevel%
for /F "tokens=* delims=0" %%Z in ("%=ExitCode%") do set "HEXCODE=%%Z"
if not defined HEXCODE set "HEXCODE=0"
echo The error level is: %HEXCODE%
...to get this:
The error level is: F
Just write it in vbscript instead of batch
put the vbscript statement below into a file.
WScript.Echo Hex( WScript.Arguments(0) )
then to run it, simple type this on the command line ( in a batch script, use a for loop to capture the value if required )
C:\workspace> cscript //nologo hex.vbs 15
F
There is no need to install anything. vbscript comes by default in most windows systems.
perl -e"printf qq{The errorlevel is: %X\n}, $ENV{ERRORLEVEL}"
Requires Perl to be installed, of course, but that's easy to do.

Resources