I'm developing an app that should build on Windows, Linux and OS X using QtCreator and Qt 5.3. I want to copy all files and subfolders from a folder into output folder. I've got it working for Linux and OS X, but not for Windows. Here's the relevant section of my .pro file:
win32 {
PWD_WIN = $${PWD}
DESTDIR_WIN = $${OUT_PWD}
copyfiles.commands = $$quote(cmd /c xcopy /S /I $${PWD_WIN}\copy_to_output $${DESTDIR_WIN})
}
macx {
copyfiles.commands = cp -r $$PWD/copy_to_output/* $$OUT_PWD
}
linux {
copyfiles.commands = cp -r $$PWD/copy_to_output/* $$OUT_PWD
}
QMAKE_EXTRA_TARGETS += copyfiles
POST_TARGETDEPS += copyfiles
The error I'm getting on Windows is "Invalid number of parameters".
If you look at the $${PWD} variable with message($${PWD}), you will see / as directory seperator, even in Windows. You have to convert it to native directory seperator :
PWD_WIN = $${PWD}
DESTDIR_WIN = $${OUT_PWD}
PWD_WIN ~= s,/,\\,g
DESTDIR_WIN ~= s,/,\\,g
copyfiles.commands = $$quote(cmd /c xcopy /S /I $${PWD_WIN}\\copy_to_output $${DESTDIR_WIN})
QMAKE_EXTRA_TARGETS += copyfiles
POST_TARGETDEPS += copyfiles
Building off of #Murat's answer, Qt actually has built-in functions to convert the filepath to the local system's preference.
$$shell_path( <your path> ) //Converts to OS path divider preference.
$$clean_path( <your path> ) //Removes duplicate dividers.
Call it like: $$shell_path($$clean_path( <your path> )), or $$clean_path() will convert the dividers back to Linux-style dividers.
This works for me on Windows:
#For our copy command, we neeed to fix the filepaths to use Windows-style path dividers.
SHADER_SOURCE_PATH = $$shell_path($$clean_path("$${SOURCE_ROOT}\\Engine\\Shaders\\"))
SHADER_DESTINATION = $$shell_path($$clean_path("$${PROJECT_BIN}\\Shaders\\"))
#Create a command, using the 'cmd' command line and Window's 'xcopy', to copy our shaders folder
#into the Game/Bin/Shaders/ directory.
CopyShaders.commands = $$quote(cmd /c xcopy /Y /S /I $${SHADER_SOURCE_PATH} $${SHADER_DESTINATION})
#Add the command to Qt.
QMAKE_EXTRA_TARGETS += CopyShaders
POST_TARGETDEPS += CopyShaders
Related
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)
I have a pure QML application where I'm trying to create a folder with a QProcess on Windows.
If the path I'd like to create contains a space it is working.
If the path I'd like to create DOES NOT contain a space it is NOT working.
QML function:
function mkdir(qproc, path) {
var cmd;
var res = false;
// Platform-based command
switch (Qt.platform.os) {
case "windows":
cmd = "cmd /s /c mkdir \"" + path + "\"";
break;
default:
cmd = "/bin/sh -c \"mkdir -p '"+path+"'\"";
}
qproc.start(cmd);
res = qproc.waitForFinished(5000);
}
Which ends up as DOS commands:
Path with space: cmd /s /c mkdir "D:/Misc/temp/A Folder/" ==> A Folder is created
Path without space: cmd /s /c mkdir "D:/Misc/temp/AFolder/" ==> AFolder is NOT created
Two remarks:
the \s flag seems having no effect, neither positive nor negative (I could remove it)
launched individually in a cmd-prompt, the 2 calls are working. The issue seems to be in the QML<->cmd interaction.
I have some document in a folder. these document may have same name with different extention, e.g: xyz.doc, xyz.pdf and xyz.log. I want implement following logic in windows command line script:
foreach *.doc {
if EXIST *.pdf{
do something_1
}else {
do something_2
}
if EXIST *.log {
do something_3
}
Here's my Minimal, Complete, and Verifiable example (Copy&Paste from cmd window). Used another extensions but principle is the same:
==> dir /b "sta *.*"
sta tus.csv
sta tus.txt
sta tus2.txt
==> for %G in ("sta *.txt") do #if exist "%~nG.csv" (echo + %~nG ) else (echo - %~nG)
+ sta tus
- sta tus2
==>
A batch script for your extensions:
#echo off
for %%G in ("*.doc") do (
if exist "%%~nG.pdf" (
echo + %%~nG
) else (
echo - %%~nG
)
)
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, %~nG etc. special page) Command Line arguments (Parameters)
Does anybody know why the below happens and does anybody have a workaround?
I'm strugging to capture mklink command output (via cmd.exe mklink > out.txt)
Output is sent to out.txt fine if the mklink command is successful
E.G: %comspec% /c mklink /d C:\Test C:\Windows > out.txt && notepad out.txt
However if the command is invalid, or fails, then nothing will be written to out.txt
E.G: Run above command again (fails because C:\Test already exists) or
E.G: %comspec% /c mklink > out.txt && notepad out.txt
I'm using the command in VBScript, does anybody know how to capture the mklink output if the command isn't completed successfully?
Set o_shell = CreateObject("Wscript.Shell")
Set o_fso = CreateObject("Scripting.FileSystemObject")
mklinkCommandOutput = GetCommandOutput("mklink /D ""C:\Test"" ""C:\Windows""")
WScript.echo mklinkCommandOutput
Function GetCommandOutput(runCmd)
on error resume next
Dim o_file, tempFile: tempFile = o_shell.ExpandEnvironmentStrings("%TEMP%") & "\tmpcmd.txt"
' Run command and write output to temp file
o_shell.Run "%COMSPEC% /c " & runCmd & " > """ & tempFile & """", 0, 1
' Read command output from temp file
Set o_file = o_fso.OpenTextFile(tempFile, 1)
GetCommandOutput = o_file.ReadAll
o_file.Close
' Delete temp file
Set o_file = o_fso.GetFile(tempFile)
o_file.Delete
End Function
(1) According to Using multiple commands and conditional processing symbols, the symbol && runs the command on the right only if the command on the left succeeds. You must use &
to start notepad even when the mlink fails.
(2) While the mlink docs don't say so explicitly, I assume that mlink writes its error message to Stderr (see here) - just like dir.
Evidence:
dir 01.vbs
...
19.10.2012 11:29 2.588 01.vbs
...
(dir succeeded)
dir nix
...
File Not Found
(dir failed)
dir nix && echo nothing to see, because lefty failed
...
File Not Found
(dir failed, no output because of &&)
dir nix & echo much to see, although lefty failed
...
File Not Found
much to see, although lefty failed
(dir succeeded, echo done because of &)
(3) To capture the output of mlink (rsp. dir) whether it fails or not and to display the result (file) in notepad, you have to use
dir 01.vbs 1> out.txt 2>&1 & notepad out.txt
dir nix 1> out.txt 2>&1 & notepad out.txt
to redirect Stdout and Stderr to the output file.
Evidence:
Have you considered utilizing the "Exec" command rather than the run command and collecting the output results?
It doesn't require a file and it's just easier.
New Code
Function GetCommandOutput(runCmd)
Dim WshShell, oExec
Set WshShell = CreateObject("WScript.Shell")
Set oExec = WshShell.Exec("%COMSPEC% /c " & runCmd)
GetCommandOutput = oExec.StdOut.ReadAll
End Function
Old Code
Function GetCommandOutput(runCmd)
on error resume next
Dim o_file, tempFile: tempFile = o_shell.ExpandEnvironmentStrings("%TEMP%") & "\tmpcmd.txt"
' Run command and write output to temp file
o_shell.Run "%COMSPEC% /c " & runCmd & " > """ & tempFile & """", 0, 1
' Read command output from temp file
Set o_file = o_fso.OpenTextFile(tempFile, 1)
GetCommandOutput = o_file.ReadAll
o_file.Close
' Delete temp file
Set o_file = o_fso.GetFile(tempFile)
o_file.Delete
End Function
I admit I am a noob when it comes to CMD and bat scripting hence maybe my question has already been answered but I couldn't find it because I am unfamiliar with the terminology.
Basically I am currently running CMD to create a txt file for a directory content, that works fine but I would like to improve this process and started to look into a batch file to run this for multiple directories and by date but only get confused with the commands.
I would really appreciated if you maybe show me the right direction to look up the possible commands. Here is was I am basically trying to achieve:
Scan Directory 1, create log file with all content (filename) with modification of date DDMMYYYY and save under Directory 1 (existing on Desktop)
Repeat above for Directory 2, 3, 4 etc.
Now I am not sure how to approach this and where to start. It looks so simply yet I am have not managed to get to work.
assuming you are on Vista or better and your date format is dd/mm/yyyy:
for /d %%a in ("%userprofile%\Desktop\Directory*") do (
for %%b in ("%%~fa\*") do (
set "fname=%%~fb"
for /f %%c in ("%%~tb") do set "fdate=%%c"
setlocal enabledelayedexpansion
echo !fname! !fdate:/=! >> "%%~fa\LOGFILE.TXT"
endlocal
)
)
First of all your batch script to parse current date-time will be locale specific. As long as you do not plan to use it on non-US Windows it will be fine. My solution was to use simple VBS script to generate current timestamps
So code of my batch file looks like
#echo off
call GetToday.bat
call %TEMP%\SetToday.bat
SET LOGFILE=Log.%TODAY%.log
echo %LOGFILE%
Use your log here
GetToday.bat:
#echo off
set TOOLS_HOME=%~dp0
cscript /NoLogo %TOOLS_HOME%\Today.vbs >%TEMP%\SetToday.bat
call %TEMP%\SetToday.bat
Today.vbs:
Dim d
d = Now
WScript.Echo "SET TODAY=" & Get2Digit(Year(d)) & Get2Digit(Month(d)) & Get2Digit(Day(d))
Function Get2Digit(value)
if 10 > value Then
Get2Digit = "0" & value
Else
Get2Digit = Right(value, 2)
End If
End Function
However given Today.vbs generates today date in form YYMMDD. From my experience such suffixes are much more useful, you could just sort you files by name to find specific date
In PowerShell something like this should work:
$folders = 'C:\path\to\Directory1', 'C:\path\to\Directory2', ...
$refDate = (Get-Date '2013-05-27').Date
$recurse = $false
foreach ($d in $folders) {
$output = Join-Path $d 'filelist.txt'
Get-ChildItem $d -Recurse:$recurse | ? {
-not $_.PSIsContainer -and $_.LastWriteTime.Date -eq $refDate
} | % { $_.Name } | Out-File $output
}
If you want to recurse into the subfolders of the scanned folders you need to change $recurse to $true and perhaps change $_.Name to $_.FullName, so you get the filename with the full path instead of just the filename.