ruaok
ruaok

Reputation: 45

Microsoft batch file not passing arguments to subroutine

The following batch file is not correctly passing the variables %%a, %%b, %%c to subroutine correctly.

@echo off
enter code here`setlocal EnableDelayedExpansion

FOR /F "tokens=1,2,3 delims= " %%a in (ftp_config.txt) do (
  echo %%a
  echo %%b
  echo %%c
  call :SUB_ftp_cmd %%a %%b %%c
  )
exit

:SUB_ftp_cmd
echo open %1>ftp.txt
echo %2>>ftp.txt
echo %3>>ftp.txt
echo cd /public_html>>ftp.txt
echo bin>>ftp.txt
echo hash>>ftp.txt
echo put "test.txt">>ftp.txt
echo close>>ftp.txt
echo bye>>ftp.txt

c:\windows\system32\ftp.exe -i <ftp.txt

del ftp.txt

exit /b

ftp.config contains the following:

domain_name1 username1 password1
domain_name2 username2 password2

The content of ftp.txt ends up being:

open 
ECHO is off.
ECHO is off.
cd /public_html
bin
hash
put "test.txt"
close
bye

I've put a few lines in as debug and see that %%a, %%b, %%c are being assigned correctly in the FOR loop, but are not passed to SUB_ftp_cmd correctly.

Updated the batch file to:

@echo off
setlocal DisableDelayedExpansion
FOR /F "tokens=1,2,* delims=      " %%a in (ftp_config.txt) do (
  echo(=== for loop variables: a=[%%a], b=[%%b], c=[%%c]
    set "passw=%%c"
    call :SUB_ftp_cmd %%a %%b
  )
exit /B

:SUB_ftp_cmd
SETLOCAL EnableDelayedExpansion
>ftp.txt (
echo open %1
echo(%2
echo(!passw!
echo cd /public_html
echo bin
echo hash
echo put "test.txt"
echo close
echo bye
)
ENDLOCAL
echo(=== ftp.txt content
type ftp.txt
echo(=== ftp command is merely displayed using `ECHO`
ECHO c:\windows\system32\ftp.exe -i -s:ftp.txt
echo(
rem del ftp.txt
exit /b

ftp_config.txt has:

"ftp.domain1.com" username1 pas3&^#%$
"ftp.domain2.com" username2 passworks

resulting ftp.txt:

open "ftp.domain2.com"
username2

cd /public_html
bin
hash
put "test.txt"
close
bye

Any help is appreciated.

Upvotes: 2

Views: 87

Answers (1)

JosefZ
JosefZ

Reputation: 30123

I can reproduce very similar results if there is an seemingly empty line in the ftp_config.txt file even thought it contains (one or more) <tab> (Character Tabulation).
Let's argue against "tokens=1,2,3 delims= " clause:

  • If you specify "delims=<space>" (Unicode codepoint U+0020) then for /F tokenization will fail for <tab> (codepoint U+0009) and vice versa.
  • If you don’t specify delims it will default to "delims=<tab><space>".
  • Hence, you could specify "tokens=1,2,*" omitting delims at all.
  • Unfortunately, there is another extra invisible space-like character   (No-Break Space, codepoint U+00A0) which is not a valid delimiter.

Conclusion: use "delims=<tab><No-Break Space><space>"; in terms of keyboard input (I don't know better way how-to show it here): "delims=TabAlt+0160Space".

Next script should work even if a password contains cmd poisonous characters or valid delimiters like %, &, |, <, >, !, ,, ;, = etc. (supposing that computer and user names don't contain those ones), see output below:

@echo off
setlocal DisableDelayedExpansion
rem FOR /F "tokens=1,2,*" %%a in (ftp_config.txt) do (
rem in next line     delims=<tab><No-Break Space><space>" %%a …
FOR /F "tokens=1,2,* delims=      " %%a in (ftp_config.txt) do (
  echo(=== for loop variables: a=[%%a], b=[%%b], c=[%%c]
    set "passw=%%c"
    call :SUB_ftp_cmd %%a %%b
  )
exit /B

:SUB_ftp_cmd
SETLOCAL EnableDelayedExpansion
>ftp.txt (
echo open %1
echo(%2
echo(!passw!
echo cd /public_html
echo bin
echo hash
echo put "test.txt"
echo close
echo bye
)
ENDLOCAL
echo(=== ftp.txt content
type ftp.txt
echo(=== ftp command is merely displayed using `ECHO`
ECHO c:\windows\system32\ftp.exe -i -s:ftp.txt
echo(
del ftp.txt
exit /b

Output:

==> D:\bat\SO\37648941.bat
=== for loop variables: a=[domain_name1], b=[username1], c=[pass&,!%word1]
=== ftp.txt content
open domain_name1
username1
pass&,!%word1
cd /public_html
bin
hash
put "test.txt"
close
bye
=== ftp command is merely displayed using `ECHO`
c:\windows\system32\ftp.exe -i -s:ftp.txt

=== for loop variables: a=[domain_name2], b=[username2], c=[pass<;!%word2]
=== ftp.txt content
open domain_name2
username2
pass<;!%word2
cd /public_html
bin
hash
put "test.txt"
close
bye
=== ftp command is merely displayed using `ECHO`
c:\windows\system32\ftp.exe -i -s:ftp.txt

==>

Upvotes: 3

Related Questions