I have several files inside different folders and I'm trying to copy them to another different folder.
For example:
[source] [dest]
C:\Users\Downloads\a\a.txt C:\Users\Downloads\222\a.txt
C:\Users\Downloads\b\b.jpg C:\Users\Downloads\333\b.jpg
C:\Users\Downloads\xyz\c.exe C:\Users\Downloads\yyy\c.exe
...
How I could create a script to be executed on cmd and using robocopy copy all files at once?
My attempt:
#echo off
set obj[0].source="C:\Users"
set obj[0].dest="C:\Users\a"
set obj[0].file="x.txt"
set obj[1].source="C:\Users"
set obj[1].dest="C:\Users\b"
set obj[1].file="y.txt"
FOR /L %%i IN (0 1) DO (
call echo source = %%obj[%%i].source%%
call echo dest = %%obj[%%i].dest%%
robocopy %%obj[%%i].source%% %%obj[%%i].dest%% %%obj[%%i].file%%
)
pause
Error:
2022/12/22 21:03:36 ERROR 2 (0x00000002) Accessing Source Directory C:\Users\%obj[0].source%\
The system cannot find the file specified.
Press any key to continue . . .
The path is wrong, whats happening?
With Powershell you can do like this :
$Paths=#{
"C:\Users\Downloads\a\a.txt"="C:\Users\Downloads\222\a.txt"
"C:\Users\Downloads\b\b.jpg"="C:\Users\Downloads\333\b.jpg"
"C:\Users\Downloads\xyz\c.exe"="C:\Users\Downloads\yyy\c.exe"
}
$Paths.GetEnumerator() | ForEach-Object {write-host Robocopy $_.Key $_.Value}
And the result is like this one :
Robocopy C:\Users\Downloads\xyz\c.exe C:\Users\Downloads\yyy\c.exe
Robocopy C:\Users\Downloads\a\a.txt C:\Users\Downloads\222\a.txt
Robocopy C:\Users\Downloads\b\b.jpg C:\Users\Downloads\333\b.jpg
Further reading : Read all items in a PowerShell hash table with a loop
EDIT : Tested with xcopy
$Paths=#{
"E:\Batch\SpeedTest\Shortcut-PS.bat"="E:\temp\a\"
"E:\Batch\SpeedTest\SpeedTest_Hackoo_Ookla.bat"="E:\temp\b\"
"E:\Batch\SpeedTest\OLD_SpeedResult.txt"="E:\temp\c\"
}
$Paths.GetEnumerator() | ForEach-Object {xcopy /D $_.Key $_.Value}
Results :
E:\Batch\SpeedTest\SpeedTest_Hackoo_Ookla.bat
1 fichier(s) copi‚(s)
E:\Batch\SpeedTest\OLD_SpeedResult.txt
1 fichier(s) copi‚(s)
E:\Batch\SpeedTest\Shortcut-PS.bat
1 fichier(s) copi‚(s)
Basically I am trying to check if a certain PostgreSQL DB exists with a batch file from the CMD in Windows. Then output custom results onto a text file within the same location, the text file will contain custom values. But the batch I created keeps giving me this (below), does not create the file and instead outputs this on the cmd:
SET _chk_DB=server
was unexpected at this time.
And I would like to know where I went wrong.
I am a beginner with batch so please do take that into consideration.
SET _chk_DB=server
FOR /F "usebackq" %%S IN (psql.exe -h %_svr% -d %_db% -U %_usr%
-P %_psw%
-Q "set nocount on; select count(*) from dbo.sysdatabases where
[name]='%_dtb%'") DO ( SET _chk_DB=%%S )
IF [%_chk_DB%]==[server]
"1" >> Info.text
else
echo "0" >> Info.txt
IF [%_chk_DB%]==[login]
"1" >> Info.text
else
echo "0" >> Info.txt
IF [%_chk_DB%]==[0]
"1" >> Info.text
else
echo "0" >> Info.txt
I have one batch file MyTest.bat
MyTest.bat
call "first.bat"
call "second.bat"
call "third.bat"
Now while executing MyTest.bat I will pass comma separated parameters like
call MyTest.bat first.bat,second.bat
now inside MyTest.bat I want to check which parameters are passed and based on those using if else condition
I want to execute internal statements.
for example something like it
MyTest.bat first.bat,second.bat
now inside
I will check
get all parameters list param[] = {first.bat,second.bat}
if param[i] == "first.bat"
{
call "first.bat"
}
else if param[i] == "second.bat"
{
call "second.bat"
}
else if param[i] == "third.bat"
{
call "third.bat"
}
// this assures that what parameters I passed only those statements gets executed not other.
The above code is just a pseudo code how can write actual MyTest.bat?
Next script requires another parameter order (list of batch names down to end all other parameters):
#ECHO OFF
SETLOCAL EnableExtensions
rem usage: 33955749.bat name address "first script", second, third
:loop
if "%~3" == "" goto :next
if exist "%~n3.bat" (
call "%~n3.bat" %1 %2
) else (
echo can't found file; failed call "%~n3.bat" %1 %2
)
shift /3
goto :loop
:next
For debugging purposes, prepare sample files "first script.bat" and second.bat; ensure that third.bat does not exist:
==> >"first script.bat" echo #echo %~nx0 parameters: %%*=%*
==> >second.bat echo #echo %~nx0 parameters: %%*=%*
==> 2>NUL del third.bat
Output (shows independency on used delimiters):
==> 33955749 name address "first script", second, third
first script.bat parameters: %*=name address
second.bat parameters: %*=name address
can't found file; failed call "third.bat" name address
==> 33955749 name address "first script" second; third
first script.bat parameters: %*=name address
second.bat parameters: %*=name address
can't found file; failed call "third.bat" name address
Another approach: fist parameter = list of comma-separated batch names surrounded with a pair of double quotes:
#ECHO OFF
SETLOCAL EnableExtensions
rem usage: 33955749b "first script,second,third" name address
rem no spaces surrounding commas or names
rem wrong: 33955749b " first script , second, third" would fail
set "_names=%~1"
set "_names=%_names:,=","%"
rem debug echo _names="%_names%"
for %%G in ("%_names%") do (
if exist "%%~dpnG.bat" (
call "%%~dpnG.bat" %2 %3
) else (
echo can't found script; failed call "%%~dpnG.bat" %2 %3
)
)
Output (shows responsivity to used delimiters):
==> 33955749b "first script,second,third" name address
first script.bat parameters: %*=name address
second.bat parameters: %*=name address
can't found script; failed call "D:\bat\SO\third.bat" name address
==> 33955749b "first script, second,third" name address
first script.bat parameters: %*=name address
can't found script; failed call "D:\bat\SO\ second.bat" name address
can't found script; failed call "D:\bat\SO\third.bat" name address
Note that both 33955749.bat and 33955749b.bat scripts
accept (partially or fully qualified) paths to called scripts, even with space(s);
on the other hand, they both ignore file extension(s) even if supplied and force .bat.
For instance, 33955749 name address first.cmd second.cmd would attempt to call first.bat and second.bat.
Resources (required reading, incomplete):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~G, %~1 etc. special page) Command Line arguments (Parameters)
(%variable:StrToFind=NewStr% etc.) Variable Edit/Replace
I have a situation in which i have to list file which is of the type as
databaseName.schemaName#1234sdf2323.lock where _Database_Name and _target_schema_name
_lockFolder are variables
# is a token then it is followed by the random alphanumeric number and the same is end with .lock .
I have acheived this in batch file through the code as
FOR /R %_lockFolder% %%F in (%_Database_Name%.%_target_schema_name%#*.lock) do (
for /f "tokens=1* delims=# " %%G IN ("%%~nF") DO (
SET _no=%%H
)
)
but when i am changing it into bash enviorment so that it can run on unix enviorment
for entry in "${_lockFolder}"/*
do
echo ENTRY "$entry"
name='${_lockFolder}/${_Database_Name}.${_target_schema_name}#*.lock'
ls -l $name > "${lockFolder}"
if [ "$?" -eq "0" ]
then
echo "Do your work here"
else
echo "No files are there for the given pattern"
fi
# exit 21
done
It is not able to recognize the pattern . The files are present in the folder which i have specified
you can simple write a for loop like,
for file in `find ${lockdir} -name "^${_lockFolder}/${_Database_Name}.${_target_schema_name}#*.lock$"`
do
echo $file
:
:
your job
done
example,
[root#giam20 unix]# ls
checksumupdator.sh GIAMMEFProcessor.sh GIAMRoleExtractor.sh
GIAMAccountExtractor.sh GIAMMetaDataLoader.sh GIAMRoleLoader.sh
GIAMAccountLoader.sh GIAMOOPControlledAttrExtractor.sh GIAMRoleMappingLoader.sh
GIAMAccountTransferLoader.sh GIAMOOPControlledAttrsLoader.sh
[root#giam20 unix]# find . -name "GIAM*.sh"
./GIAMAccountTransferLoader.sh
./GIAMIntermediateCodeUpgrader.sh
./GIAMServiceUpdator.sh
./GIAMOOPControlledAttrsUpdator.sh
./GIAMRoleUpdator.sh
./GIAMProvisioningPolicyExtractor.sh
./GIAMCompExemptionExtractor.sh
./GIAMApprovalNotificationLoader.sh
In Unix shell scripting, variable references are not resolved in a string that is enclosed in single quotes. Therefore, in this line
name='${_lockFolder}/${_Database_Name}.${_target_schema_name}#*.lock'
the value will be stored into name literally, including all the ${name} references. It is no surprise then that the pattern is not matched later.
So, just change the single quotes to double quotes:
name="${_lockFolder}/${_Database_Name}.${_target_schema_name}#*.lock"
is there anything that mimicks a method like one knows it from Java, C# etc.? I have 5 lines of commands in a batch file, those 5 lines are used at more than one place inside the batch file. I can't use a goto, because depending on the errorlevel created by those 5 lines I have different actions that follow. I tried putting my 5 lines inside a batch file 5lines.bat, but the original batch file original.bat only calls 5lines.bat and doesn't execute the commands after the call to 5lines.bat ): That's how my original.bat looks like:
5lines.bat
echo this gets never called, how to make sure this gets called?
There's no exit or something like this in 5lines.bat! How can I make sure the line after 5lines.bat gets called?
You could use the call command :
call:myDosFunc
And then define the function this way :
:myDosFunc - here starts the function
echo. here the myDosFunc function is executing a group of commands
echo. it could do a lot of things
goto:eof
Source : Batch Functions
Just for completeness, you can also pass parameters to the function:
Function call
call :myDosFunc 100 "string val"
Function body
:myDosFunc
echo. Got Param#1 %~1
echo. Got Param#2 %~2
goto :eof
Placing the reusable functions into a separate batch file would certainly work to simulate a function.
The catch is that you have to use the call command in order to ensure that control returns to the caller after the second batch file finishes executing.
call 5lines.bat
echo this will now get called
Solution:
#ECHO OFF
call:header Start Some Operation
... put your business logic here
... make sure EXIT below is present
... so you don't run into actual functions without the call
call:header Operation Finished Successfully
EXIT /B %ERRORLEVEL%
:: Functions
:header
ECHO =================================================
ECHO %*
ECHO =================================================
EXIT /B 0
Important to put EXIT /B at the end of each function, as well as before function definitions start, in my example this is:
EXIT /B %ERRORLEVEL%
You could try to use the examples listed on DOS Batch - Function Tutorial
Alternatively, you could put the common lines into another batch file that you call from the main one
Coming from a Java background, I have tried to incorporate some familiar conventions when creating procedures for .bat scripts.
The script below demonstrates the definition of two procedures.
#ECHO OFF
SET firstInstanceVariable="Hello world!"
SET secondInstanceVariable="Good bye world!"
GOTO:MAIN
:firstMethodName
SETLOCAL ENABLEDELAYEDEXPANSION
SET firstArgumentPassedIn=%~1
SET secondArgumentPassedIn=%~2
ECHO %firstInstanceVariable%
ECHO "The first argument passed in was %firstArgumentPassedIn%"
ECHO "The second argument passed in was %secondArgumentPassedIn%"
ENDLOCAL
EXIT /B 0
:secondMethodName
SETLOCAL ENABLEDELAYEDEXPANSION
SET firstArgumentPassedIn=%~1
SET secondArgumentPassedIn=%~2
ECHO %secondInstanceVariable%
ECHO "The first argument passed in was %firstArgumentPassedIn%"
ECHO "The second argument passed in was %secondArgumentPassedIn%"
ENDLOCAL
EXIT /B 0
:MAIN
call:firstMethodName "The Quick Brown" "Fox Jumps Over"
call:secondMethodName "1 2 3 4" 3.14
Notice that an explicit GOTO:MAIN is necessary to skip over the procedure definitions.
This is because you must skip over the procedure before deciding to read it. Otherwise, the procedure will be executed.
The code below demonstrates a close Java-equivalent of the above .bat script.
public class MyObject {
private String firstInstanceVariable = "Hello world!";
private String secondInstanceVariable = "Good bye world!";
public void firstMethodName(Object... arguments) {
String firstArgumentPassedIn = arguments[0].toString();
String secondArgumentPassedIn = arguments[1].toString();
System.out.println(firstInstanceVariable);
System.out.format("The first argument passed in was %s", firstArgumentPassedIn);
System.out.format("The second argument passed in was %s", secondArgumentPassedIn);
}
public void secondMethodName(Object... arguments) {
String firstArgumentPassedIn = arguments[0].toString();
String secondArgumentPassedIn = arguments[1].toString();
System.out.println(secondInstanceVariable);
System.out.format("The first argument passed in was %s", firstArgumentPassedIn);
System.out.format("The second argument passed in was %s", secondArgumentPassedIn);
}
public static void main(String[] args) {
MyObject myObject = new MyObject();
myObject.firstMethodName("The Quick Brown", "Fox Jumps Over");
myObject.secondMethodName(new Integer[]{1,2,3,4}, 3.14);
}
}
Here's a 'hack' that will allow you to have "anonymous" functions in batch files:
#echo off
setlocal
set "anonymous=/?"
:: calling the anonymous function
call :%%anonymous%% a b c 3>&1 >nul
:: here the anonymous function is defined
if "%0" == ":%anonymous%" (
echo(
echo Anonymous call:
echo %%1=%1 %%2=%2 %%3=%3
exit /b 0
)>&3
::end of the anonymous function
The anonymous function block should be placed right after the call statement and must end with exit statement
the trick is that CALL internally uses GOTO and then returns to the line where the CALL was executed. With the double expansion GOTO help message is triggered (with %%/?%% argument) and then continues the script. But after it is finished it returns to the CALL - that's why the if statement is needed.
For another great tutorial on writing reusable batch file code -- see Richie Lawrence's excellent library.
I'm not sure if it was obvious from other answers but just to be explicit I'm posting this answer. I found other answers helpful in writing below code.
echo what
rem the third param gives info to which label it should comeback to
call :myDosFunc 100 "string val" ComeBack
:ComeBack
echo what what
goto :eof
:myDosFunc
echo. Got Param#1 %~1
echo. Got Param#2 %~2
set returnto=%~3
goto :%returnto%
Below may make it look like a function.
call :myFunc %para1% %para2%
:myFunc <para1> <para2>
echo %1
echo %2
EXIT /B
Example
#echo off
echo PROGRAM_NAME:%~nx0 Start
echo.
================================
SET debugMode=%1
call :myFunc1 %debugMode%
call :myFunc2 para1 "para2 hello"
================================
echo PROGRAM_NAME:%~nx0 End & pause>nul
EXIT /B
:: 👇 define the function under below
:myFunc1 <isDebug>
:: So that you can know the %1 means: isDebug.
if "%1" == "1" (
echo debug mode
)
EXIT /B
:myFunc2 <para1> <para2>
:: output: para1
echo %1
:: output: "para2 hello"
echo %2
EXIT /B