I'm trying to write a small script to find the absolute path of Rscript in a machine running Windows OS. I assume that Rscript must be found under C:\Program Files\R\R-x.x.x directory, where x.x.x represents any version of R. I have written the following script based on several threads (Find file and return full path using a batch file).
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
for /d %%a in ("C:\Program Files\R\") do (
if "%%~nxa"=="Rscript.exe" (
set p=%%~dpnxa
)
)
Unfortunately, the if condition assigns p to every file and folder in C:\Program Files\R\R-x.x.x. If anyone has any idea of how to find and assign p properly, I would really appreciate it!
Regards,
Juan
EDIT
I'm adding my full script
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
for /R %%a in ("C:\Program Files\R\R-*") do (
if /i "%%~nxa"=="Rscript.exe" (
set "p=%%~fa"
)
)
if defined p (
echo %p%
) else (
echo File not found
)
%p% runShinyApp.R 1> ShinyApp.log 2>&1
Not sure why you want to do %%~dpnxa when you can just do %%~fa anyway, here are some ways.
#echo off
for %%a in ("C:\Program Files\R\*") do (
if /i "%%~nxa"=="Rscript.exe" (
set "p=%%~fa"
)
)
another method is to use where, without having to do an if statement, simply because you specify the executable in the where search. You can recursively search for the path in an entire drive, or specify a path, here for instance we recursively search in "C:\Program Files".
#echo off
for /f "delims=" %%a in ('where /r "%programfiles%" "rscript.exe"2^>nul') do set "p=%%~fa"
EDIT after your comments, this should work.
#echo off
for /f "delims=" %%a in ('where /r "%programfiles%\R\R-3.6.3\bin\x64" "rscript.exe"2^>nul') do "%%~fa" runShinyApp.R 1> ShinyApp.log
I would however recommend you specify the path to runShinyApp.R in the do line.
Related
Given a directory tree like:
parent
dir-v0.1.0
subdir
dir-v0.2.0
subdir
dir-v0.3.0 # lacks subdir
I need a Windows batch sequence (for Win7+) that works like this Unix Bash code:
found=$(ls -dt ../dir-v0.*.0/subdir | head -1)
if [ "$found" ]; then
...
fi
A Powershell subcommand is an option. (Sadly powershell scripts don't launch on double-click.)
Command-shell wildcards can only appear in the last path element, so this doesn't work:
dir /o:d ..\dir-v0.*.0\subdir
EDIT: This works, using powershell:
setlocal EnableDelayedExpansion
set findSub=get-item ..\dir-v0.*.0\subdir ^| ^
sort -property LastWriteTime ^| ^
select -last 1 -expandproperty FullName
set findSub=powershell -noprofile -command "!findSub!"
for /f "delims=" %%V in ('!findSub!') do set found=%%V
if defined found (...)
The batch file below can be used to get the full qualified name of the version directory in parent directory of the batch file directory containing a subdirectory subdir with the second number being the greatest number of all version directories with a subdirectory subdir as long as the second number in version string has never one or more leading zeros.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "PreviousVersion=-1"
set "VersionDirectory="
for /D %%I in ("%~dp0..\dir-v0.*.0") do if exist "%%I\subdir\" (
for /F "tokens=2 delims=." %%J in ("%%~nxI") do (
set "CurrentVersion=%%J"
setlocal EnableDelayedExpansion
if !CurrentVersion! GTR !PreviousVersion! (
endlocal
set "VersionDirectory=%%I"
set "PreviousVersion=%%J"
) else endlocal
)
)
if defined VersionDirectory (
echo Directory with greatest version number containing subdir is:
echo/
echo "%VersionDirectory%"
) else (
echo Could not find any version directory with subdir.
)
echo/
pause
endlocal
The batch file can be faster if it is guaranteed that the path to the version directories never contains one or more exclamation marks.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "PreviousVersion=-1"
set "VersionDirectory="
for /D %%I in ("%~dp0..\dir-v0.*.0") do if exist "%%I\subdir\" (
for /F "tokens=2 delims=." %%J in ("%%~nxI") do (
if %%J GTR !PreviousVersion! (
set "VersionDirectory=%%I"
set "PreviousVersion=%%J"
)
)
)
if defined VersionDirectory (
echo Directory with greatest version number containing subdir is:
echo/
echo !VersionDirectory!
) else (
echo Could not find any version directory with subdir.
)
echo/
pause
endlocal
Delayed expansion is enabled for the entire batch file in this case.
Note: Command FOR with option /D ignores directories with hidden attribute set.
Remove %~dp0 and modify set "VersionDirectory=%%I" to set "VersionDirectory=%%~fI" if the used batch file should run on parent directory of current directory independent on storage location of the batch file.
The condition if exist "%%I\subdir\" can be removed if it should not matter if the version directory contains already the subdirectory subdir or not.
The following code can be used to get the file name without path of newest file in subdirectory subdir of the version directory with greatest version number:
set "NewestFile="
for /F "eol=| delims=" %%K in ('dir "%VersionDirectory%" /A-D /B /O-D /TW 2^>nul') do set "NewestFile=%%K" & goto HaveNewestFile
:HaveNewestFile
if not defined NewestFile (
echo Failed to find a file in directory: "%VersionDirectory%"
) else (
echo Newest file in "%VersionDirectory%" is: "%NewestFile%"
)
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains %~dp0 ... drive and path of argument 0 which is the batch file directory path always ending with a backslash.
dir /?
echo /?
endlocal /?
for /?
if /?
pause /?
set /?
setlocal /?
My requirement is to write a batch script to find and replace the a string in all of the *-spec.js files in given set of directories. Hence I have written the batch file and running the batch script as below.
<script file name> <search_string> <replace_string> <folder_path_1> <folder_path_2> <folder_path_n>
(I am sure the folder_path_n will not go beyond 7)
e.g C:\CI\Scripts>replace.bat hello world C:\app\e2e C:\sppa\e2e
So my script is as below.
#echo off
setlocal enabledelayedexpansion
set argCount=0
for %%x in (%*) do (
set /A argCount+=1
set "argVec[!argCount!]=%%~x"
)
set search=%1
set replace=%2
echo Search is %search%
echo Replace is %replace%
for /L %%i in (3,1,%argCount%) do (
set path=!argVec[%%i]!
echo path is !path!
for /R !path! %%F in (*spec.js) do (
echo %%F
)
)
Here it prints the 4 arguments correctly even the path is also printed as expected. In the next step it's expected to loop through the given path and gets all of the files that ends with "spec.js".
e.g not working:
for /R !path! %%F in (*spec.js) do (
echo %%F
)
But it prints nothing. Instead if the variable is replaced with hard coded value, it works as expected.
e.g - working:
for /R C:\app\sppa\e2e %%F in (*spec.js) do (
echo %%F
)
Your help is highly appreciated!
The reason it's not working is that the variable content must be known when the loop is parsed means that it only works with variables that can be expanded without delayed expansion. Nevertheless there is an easy solution as a for /r loop is working with the current path (from ss64).
If the [drive:]path are not specified they will default to the current drive:path.
Just change directory to !path! and then go back:
rem Change into !path! and remember directory coming from
pushd !path!
for /R %%F in (*spec.js) do (
echo %%F
)
rem Change back to origin
popd
I also tried similar as suggested by #Andre Kampling as below.
cd !path!
::echo Changed the path to !path!
FOR /R %%F IN (*spec.js) DO (
echo %%F
)
To list the directories I use this:
set folder=C:\temp
for /d %%a in ("%folder%\*") do (
echo %%~fa
)
To splith the file path I use this:
for %%f in (%MYDIR1%) do set myfolder=%%~nxf
echo %myfolder%
Now I want put both together:
#echo off
set folder=C:\Windows
for /d %%A in ("%folder%\*") do (
for %%d in (%%~fA) do set lastfolder=%%~nxf
echo %lastfolder%
)
All I get in thes result is %~nxf. I tried some things, but I didn't get a correct result. What I'm doing wrong?
What I don't understand in these examples is %~fA and %~nxf. Don't know where you can look up things like this.
Edit:
%~nxf to get file names with extensions
where F is the variable and ~n is the request for its name | Source
%~fI Expands %I to a fully qualified path name.
Now I modified my code with the new information:
#echo off
for /d %%A in ("%folder%\*") do (
for %%D in (%%~fA) do (
set lastfolder=%%~nxD
echo %lastfolder%
)
)
Now I get as result the last folder, but this is printed as many times as subfolders are existing. So I only get the last one. How can I iterate over each?
Solution:
Thanks to bgalea this is my solution:
#echo off
setlocal enabledelayedexpansion
set folder=C:\Windows
for /d %%A in ("%folder%\*") do (
for %%D in (%%~fA) do (
set lastfolder=%%~nxD
echo !lastfolder!
)
)
endlocal
Things in bracket are one line. Therefore you have to use !var! which you turn on with setlocal enabledelayedexpansion. See set /? and setlocal /?.
. is current directory and .. is parent directory.
So c:\temp\.. is the same as c:\
%~nx1 etc are documented in the call command's help - call /?
My answer here Trouble with renaming folders and sub folders using Batch has a list of command prompt punctuation.
OK, I apologize ahead of time for a) using an old, crappy technology (BAT files) and b) asking what seems to be a redundant question. I'm limited in the technology I'm allowed to use in this particular case and after looking at dozens of posts on the subject I can't find anything I can adapt to what I need.
I have a directory structure that looks like this:
A
B
C
D
etc...
XYZ
more folders
My BAT file is located outside this files system. I need to inspect it starting at level "C" and need to find the "XYZ" directory. The folders between C and XYZ can have variable names depending on the environment in which the files were created. I need to end up with a string that consists of the directory names from C through XYZ (i.e. "C\D\E\F....\XYZ") that I can put into a variable so when my BAT file is completed I can reference the variable and run another command.
I've looked at posts using FIND and FOR but I can't seem to figure out how to a) limit the string to the starting directory (for example when I combine FOR with DIR I get "A\B\C...") and how to stop when I get to "XYZ"...
Any help is greatly appreciated.
This should work in most situations:
#echo off
setlocal enableDelayedExpansion
set "root=c:\a\b\c"
set "target=xyz"
for %%R in ("%root%") do for /f "delims=" %%F in (
'dir /b /s /ad "%root%\%target%"'
) do (
set "fullPath=%%F"
set "relpath=!fullPath:%%~dpR=!"
)
echo !relpath!
It can fail if any of your paths contain ! or =. There are solutions for this, but the code is significantly more complicated.
EDIT
Actually, there is a relatively simple solution using FORFILES that should work in all situations. (Assuming your version of Windows has FORFILES)
#echo off
setlocal disableDelayedExpansion
set "root=c:\a\b\c"
set "target=xyz"
for /f "delims=" %%F in (
'forfiles /p "%root%" /m "%target%" /s /c "cmd /c if #isdir==TRUE echo #relpath"'
) do set "relpath=%%~F"
for %%R in ("%root%") do set "relpath=%%~nxR%relpath:~1%"
echo %relpath%
The only restriction is the code has to change slightly if your result contains poison characters like &. In that case you need to add quotes to the final ECHO statement, or else enable delayed expansion at the end and use echo !relpath!
For a) question:
FOR /F "TOKENS=*" %%d IN ('DIR A\B\C\XYZ /S /AD /B') DO SET variable=%%d
For a) and b) question:
FOR /D /R "A\B\C" %%d IN (*.*) DO IF /I "%%~nxd"=="XYZ" (SET variable=%%d& GOTO :EOF)
but this will exit batch script, so you need:
... your batch code
CALL :GET_XYZ
... your batch code
GOTO :EOF
:GET_XYZ
FOR /D /R "A\B\C" %%d IN (*.*) DO IF /I "%%~nxd"=="XYZ" (SET variable=%%d& GOTO :EOF)
ECHO XYZ not found!
GOTO :EOF
Is it posible to copy and make directories automatically from file name substrings using Robocopy?
I mean i have files like these. LAJ00306130201004626.rc the first 8 chararacters are control number (LAJ00306=control number) this would be the name of the folder and the rest are the date and time (Date=130201) (time=004626).
LAJ00306130201004626.rc
LAJ00306130202004626.rc
LAJ00306130203004626.rc
LAJ00307130201004626.rc
LAJ00307130202004626.rc
and i would like to copy and create folders from the file name like under and copy the files mentioned before in the new folders.
LAJ00306
LAJ00307
I hope to be clear if necessary ask me for more information
try this, look at the output and remove the echos before MD and ROBOCOPY, if it looks good:
#ECHO OFF &SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcefolder=."
SET "targetfolder=X:\data"
CD /d "%sourcefolder%"
FOR %%a IN (*.rc) DO (
SET "fname=%%a"
SET "folder=!fname:~0,8!"
SET "$!folder!=1"
)
FOR /f "delims=$=" %%a IN ('set "$"') DO (
ECHO MD "%targetfolder%\%%a" 2>nul
ECHO ROBOCOPY "%sourcefolder%" "%targetfolder%\%%a" "%%a*.rc"
)
Set sourcefolder and targetfolder for your folder tree.
Try this:
#echo off
pushd "c:\source folder"
setlocal enabledelayedexpansion
for %%a in (*.rc) do (
set "name=%%a"
robocopy "%cd%" "%%a" "D:\target directory\!name:~0,8!"
)
popd
Answers to your questions are:
pushd "drive:\path" makes the location the current working directory.
popd restores the last working directory
setlocal enabledelayedexpansion allows you to change and use variables within a loop, using the !variable! syntax.
If your 2000 files are in a single folder then it should work - but test it on some sample files first so that you can see how it will work.
#ECHO OFF
SETLOCAL
SET "sourcedir=."
SET "destdir=c:\destdir"
FOR /f "tokens=1*delims=_" %%i IN (
'dir /b /a-d "%sourcedir%\*_*."'
) DO XCOPY /b "%sourcedir%\%%i_%%j" "%destdir%\%%i\"
GOTO :EOF
This should accomplish the task described. You'd need to set up the source and destination directories to suit, of course. Add >nul to the end of the XCOPY line to suppress 'copied' messages.