Need help reprogramming a short batch program to macOS bash - bash

I've written a batch program (long time ago now) to backup my data from one external drive to another. It scans the drive, makes a directory file of all the folders in it, and counts the number of lines (and thus folders). From there it reads from that file, one line at a time, and copies the contents of each folder in the list in the directory file to the other drive, only copying what was new or modified from the last time it copied, and if something was on the backup drive, that had been deleted from the source drive, it left it there. It just kept adding, not deleting. This was intentional, don't worry.
Here is the script:
#echo off
set /p Drive=The Archive Drive Letter:
cls
set /p Drive2=The Archive II Drive Letter:
dir %Drive%:\ /B >directory
#setlocal enableextensions enabledelayedexpansion
set lines=0
:the
set location=directory
set /a "lines = lines + 1"
set curr=1
for /F "delims=" %%a in ('type %location%') do (
for %%b in (!lines!) do (
if !curr!==%%b set foldername=%%a
)
set /a "curr = curr + 1"
)
xcopy "%drive%:\%foldername%" "%Drive2%:\THE ARCHIVE Backup\%foldername%\" /S /M /Y
timeout -t 2
goto :the
endlocal
I need help with making an identical program to run under MacOS bash.
I have experimented with the equivalent commands and researched how things are done in bash, but I have very limited experience with using MacOS.
I appreciate that some things are done differently under bash, such as drive naming. In my batch script above, I have a call for a user variable to confirm the drive letters, but that was only a failsafe in case drive letters change (as they do). However under MacOS drives are called via names, which I won't be changing so that part of the code I'm happy to remove.
In my specific case,
The source drive is located at "/Volumes/The ARCHIVE"
The destination drive is located at "/Volumes/The ARCHIVE II"
Any help is much appreciated, and I'm happy to take on any ideas that may improve my somewhat messy approach to things.
Thanks!
Edit:
I ran the command (with the -n switch), and after having some difficulties with the “bad interpreter” error, which I’ve solved, I’m returned a list of all my files on the source drive. I assume this will return to none after one backup, and only subsequent changes on the source drive??
Also, I’m returned a line that says “total size is 528045001932” I assume this is in bytes, and therefore when converted to gigabytes comes to 528GB, or 491GB (depends on 1024 vs 1000 bytes per kilobyte). Only thing is, my total amount of data on the source drive is more than that. Does that mean that rsync has missed some data, or has it skipped some of it because it found matches on the destination drive?

Just use rsync. You could set a cron job to run a bash script that rsync's one directory to another.
just save the following as something like copier.sh
#!/bin/bash
rsync -rv /Volumes/ARCH /Volumes/ARCH2
then add the file to crontab.
Check the man pages for rsync and crontab if you need help
EDIT:
I forget MacOS prefers you to use launchd now. You should read up on how to use launchd but I'll give you an example that may or may not work.
Create a plist file called something like com.directoryCopier.plist and place it in the /Library/LaunchDaemons directory. The file should look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.directoryCopier</string>
<key>ProgramArguments</key>
<array>
<string>/Users/Path/To/copier.sh</string>
</array>
<key>StartInterval</key>
<integer>86400</integer>
<key>StandardErrorPath</key>
<string>/tmp/copier.err</string>
<key>StandardOutPath</key>
<string>/tmp/copier.out</string>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Start the service by rebooting or by entering the command
sudo launchctl load /Library/LaunchDaemons/com.directoryCopier.plist
You can read more here
https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html
I probably left some stuff out but I'm sure someone will correct me.
Good luck

Related

Only with certain users: UNC paths are not supported Defaulting to windows directory

I have a batch file, whose purpose is to copy a directory from a network location and place it in the C: location of the user's system if it doesn't already exist. The problem is when the main user attempts this, the above message is displayed and the application subsequently errors out. BUT, when I run on my machine, to try and debug, it works just as it should with no problems.
I've seen a lot out there on this, but none where it works depending on the user. Also, most are about only working with network drives and not locals.
Here is the code. I am not the author of this .bat so let me know if something doesn't look quite right.
#echo off
echo Starting Application...
rem copy files over to the users local computer to prevent .dll problems when running App
C:
CD \
if not exist "C:\App" mkdir c:\App
CD App
robocopy "\\server\shared\fuller\Apps\ThisApp" c:\App /S robocopy.log
echo You may close this window or it will close by itself when the program is done.
ThisApp1.exe
I've tried using popd and pushd in various spots, but I'm not sure where I would put those, or even if it's applicable to this situation.
Put this line as the 2nd line (right after #echo off)
pushd %~dp0 & REM needed in case 'Run as Administrator' or executed from network drive
https://ss64.com/nt/pushd.html
Note that 'Run as Administrator' changes the current directory... this will put it back to where it was.

Launch shell script on login in Mac OS (OS X)

I have this shell script Test.sh:
#! /bin/bash
FILE_TO_CHECK="/Users/test/start.txt"
EXIT=0
while [ $EXIT -eq 0 ]; do
if [ -f "$FILE_TO_CHECK" ]
then
/usr/bin/java -jar myapp.jar
EXIT=1
else
sleep 30
fi
done
I need to start this script automatically after login.
So I put it inside a folder Test in /System/Library/StartupItems/
When I reboot the Mac, nothing happens after I log in.
Any clue?
I also tried Automator, but with the same result: the java program is not running.
Ivan Kovacevic's pointers, especially the superuser.com link, are helpful; since at least OS X 10.9.2, your options for creating run-at-login scripts are:
Note: The methods are annotated with respect to whether they are:
specific to a given user ("[user-SPECIFIC]"); i.e., the installation must be performed for each user, if desired; scripts are typically stored in a user-specific location, and root (administrative) privileges are NOT required for installation.
effective for ALL users ("[ALL users]"); i.e., the installation takes effect for ALL users; scripts are typically stored in a shared location and root (administrative) privileges ARE required for installation.
The scripts themselves will run invisibly, but - with the exception of the com.apple.loginwindow login-hook method - you can open applications visibly from them; things to note:
There is no guarantee that any such application will be frontmost, so it may be obscured by other windows opened during login.
If you want to run another shell script visibly, simply use open /path/to/your-script, which will open it in Terminal.app; however, the Terminal window will automatically close when your script terminates.
Automator [user-SPECIFIC]:
File > New, type Application
Add a Run Shell Script action, which adds an embedded bash script, and either paste your script code there or add a command that invokes an existing script from there.
Save the *.app bundle and add it to the Login Items list in System Preferences > User & Groups > Login Items.
Note:
The embedded script runs with the default "C" locale.
$PATH is fixed to /usr/bin:/bin:/usr/sbin:/sbin, which notably does NOT include /usr/local/bin
The working dir. is the current user's home directory.
com.apple.loginwindowlogin hook [ALL users - DEPRECATED, but still works]:
If you have admin privileges, this is the easiest method, but it is DEPRECATED, for a variety of reasons (security, limited to a single, shared script, synchronous execution); Apple especially cautions against use of this mechanism as part of a software product.
Place your script, e.g., Test.sh, in a shared location - e.g., /Users/Shared - and make sure it is executable (chmod +x /Users/Shared/Test.sh).
From Terminal.app, run the following:
sudo defaults write com.apple.loginwindow LoginHook /Users/Shared/Test.sh
Note:
The script will run as the root user, so exercise due caution.
Among the methods listed here, this is the only way to run a script as root.
There's only one system-wide login hook.
Note that there's also a log-OUT hook, LogoutHook, which provides run-at-logout functionality - unlike the other approaches.
The login-hook script runs synchronously before other login actions, and should therefore be kept short.
Notably, it runs before the desktop is displayed; you cannot launch applications from the script, but you can create simple interactions via osascript and AppleScript snippets (e.g., osascript -e 'display dialog "Proceed?"'); however, any interactions block the login process.
The script runs in the context of the root user and he username of the user logging on is passed as the 1st argument to the script.
The script runs with the default "C" locale.
$PATH is fixed to /usr/bin:/bin:/usr/sbin:/sbin, which notably does NOT include /usr/local/bin
The working dir. is /.
launchd agents:
launchd-agent-executed scripts can be installed for a SPECIFIC user OR for ALL users - the latter requires administrative privileges.
While using launchd is Apple's preferred method, it's also the most cumbersome, as it requires creating a separate *.plist configuration file.
On the upside, you can install multiple scripts independently.
Note:
No specific timing or sequencing of launchd scripts is guaranteed; loosely speaking, they "run at the same time at login"; there is even no guaranteed timing between the user-specific and the all-user tasks.
The script runs with the default "C" locale.
$PATH is fixed to /usr/bin:/bin:/usr/sbin:/sbin, which notably does NOT include /usr/local/bin
The working dir. is / by default, but you can configure it via the .plist file - see below.
The script-file path must be specified as a full, literal path (e.g., /Users/jdoe/script.sh; notably , ~-prefixed paths do not work.
For a description of all keys that can be used in *.plist configuration files, see man launchd.plist.
Both user-specific and all-users tasks run as the current user (the user logging on).
launchd [user-SPECIFIC]:
Note: Lingon 3 ($5 as of early 2014) is a GUI application that facilitates the process below, but only for user-specific scripts.
Place your script, e.g., Test.sh, in your home folder, e.g., /Users/jdoe
Create a file with extension .plist in ~/Library/LaunchAgents, e.g., ~/Library/LaunchAgents/LoginScripts.Test.plist, by running the following in Terminal.app:
touch ~/Library/LaunchAgents/LoginScripts.Test.plist
Open the file and save it with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<!-- YOUR SELF-CHOSEN *UNIQUE* LABEL (TASK ID) HERE -->
<string>LoginScripts.Test.sh</string>
<key>ProgramArguments</key>
<array>
<!-- YOUR *FULL, LITERAL* SCRIPT PATH HERE -->
<string>/Users/jdoe/Test.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
The <!-- ... --> comments indicate the places to customize; you're free to choose a label, but it should be unique - ditto for the .plist filename; for simplicity, keep the label and the filename root the same.
From Terminal.app, run the following:
launchctl load ~/Library/LaunchAgents/LoginScripts.Test.plist
Note that, as a side effect, the script will execute right away. From that point on, the script will execute whenever the CURRENT user logs on.
It is not strictly necessary to run launchctl load -- since, by virtue of the file's location, it will be picked up automatically on next login -- but it's helpful for verifying that the file loads correctly.
launchd [ALL users]
Place your script, e.g., Test.sh, in a SHARED location, e.g., /Users/Shared
Create a file with extension .plist in /Library/LaunchAgents (requires admin privileges), e.g., /Library/LaunchAgents/LoginScripts.Test.plist, by running the following in Terminal.app:
sudo touch /Library/LaunchAgents/LoginScripts.Test.plist
Open the file and save it with the following content (make sure your text editor prompts for admin privileges on demand; alternatively, use sudo nano /Library/LaunchAgents/LoginScripts.Test.plist):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<!-- YOUR SELF-CHOSEN *UNIQUE* LABEL (TASK ID) HERE -->
<string>LoginScripts.Test.sh</string>
<key>ProgramArguments</key>
<array>
<!-- YOUR *FULL, LITERAL* SCRIPT PATH HERE -->
<string>/Users/Shared/Test.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
The <!-- ... --> comments indicate the places to customize; you're free to choose a label, but it should be unique - ditto for the .plist filename; for simplicity, keep the label and the filename root the same.
From Terminal.app, run the following:
sudo chown root /Library/LaunchAgents/LoginScripts.Test.plist
sudo launchctl load /Library/LaunchAgents/LoginScripts.Test.plist
Note that, as a side effect, the script will execute right away. From that point on, the script will execute whenever ANY user logs on.
It is not strictly necessary to run launchctl load -- since, by virtue of the file's location, it will be picked up automatically on next login -- but it's helpful for verifying that the file loads correctly.
You can't just place plain scripts in that folder. You need a "specialized bundle" how Apple calls it, basically a folder with your executable, and a .plist configuration. And you should put it in /Library/StartupItems since /System/Library/StartupItems/ is reserved for the operating system. Read all about it here:
https://developer.apple.com/library/mac/documentation/macosx/conceptual/bpsystemstartup/chapters/StartupItems.html
Also note that the whole stuff is marked as deprecated technology. And that Apple is suggesting the use of launchd. There is an example how to set it up here:
https://superuser.com/questions/229773/run-command-on-startup-login-mac-os-x
launchd-oneshot is used to install script as a launchd job to run on login, with
brew install cybertk/formulae/launchd-oneshot
sudo launchd-oneshot Test.sh --on-login
Disclosure: I am the author of this package.

Run applescript in Automator

I need to start and stop a small server with automator but my knoledge is very limited. I can't manage to set the path where the file is and I don't know how to stop the server.
So far I have this:
on run
set r to display dialog "Start or stop the NINJAM server ?" buttons {"Stop", "Start"}
if button returned of r is "Start" then
#tell application "Terminal"
# activate
do shell script "cd \"/Applications/ MUSIC/ Utilities/Audio IP/NINJAM/NINJAM/NinjamOSXServer ./ninjamsrv Server.cfg\""
#end tell
else
do shell script "Stop"
end if
end run
Any help is really apprectated. Thanks in advance.
NOTE that I'm using my own path here -- I put the ninjam server folder in the top level of my Applications folder.
I had to create a 'term' file, which is a text file with this in it:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>WindowSettings</key>
<array>
<dict>
<key>ExecutionString</key>
<string>cd /Applications/NinjamOSXServer/;./ninjamsrv config.cfg</string>
</dict>
</array>
</dict>
</plist>
I saved this as LaunchNinjamSrvr.term and put it in the same folder as the ninjamsrvr. Then the script to use is:
set r to display dialog "Start or stop the NINJAM server ?" buttons {"Stop", "Start"}
if button returned of r is "Start" then
do shell script "open /Applications/NinjamOSXServer/LaunchNinjamSrvr.term"
else
do shell script "killall -INT -v ninjamsrv"
end if
[Occurs to me that I should give some explanation. Directly using the full path with the " config.cfg" parameter makes 'do shell script' choke. Splitting into two commands (but still using do shell script), like you see in the .term file, works to launch ninjamsrv, but makes the script editor (I use Smile) freeze. So that is (presumably -- I didn't want to test it by other means [script app, etc.]) a problem, and why I resorted to using the .term file. It used to be that you could, from the File menu in Terminal (as I recall), save a .term file directly, but that seems to have fallen by the way-side. So, at this point, I have a template that I use and just paste commands into the appropriate line. (But see http://discussions.apple.com/thread/3139585?start=0&tstart=0 -- wherein the technique of exporting Terminal Preference file is explained). I'm being a bit lazy in that the new form is .terminal, not .term ... anyway ...
So now all that is left is doing the actual AS script. 'open' is a basic command line command which is just like opening or double-clicking in the Finder. If, for some reason your file opens in the wrong app or doesn't open, you might need to map it to Terminal.app (in the get info window) and/or change the extension to the more up--to-date '.terminal'.
killall is like kill, designed to kill processes in various ways. I chose -INT because this is essentially like doing a control-c to interrupt the process.]

How to run batch file from network share without "UNC path are not supported" message?

I am trying to run a batch file from a network share, but I keep getting the following message: "UNC path are not supported. Defaulting to Windows directory." The batch file is located on \\Server\Soft\WPX5\install.bat. While logged in as administrator, from my Windows 7 Desktop, I navigate to \\Server\Soft\WP15\ and double click on install.bat, that's when I get the "UNC path are not supported." message. I found some suggestions online stating that mapping drive will not work, but using a symbolic link will solve this issue, but the symbolic link didn't work for me. Below is my batch file content, I would appreciate any assistance that can help me accomplish what I am trying to do. Basically, I want to be able to run the batch file from \\Server\Soft\WP15\install.bat.
Batch file content
mklink /d %userprofile%\Desktop\WP15 \\server\soft\WP15
\\server\soft\WP15\setup.exe
robocopy.exe "\\server\soft\WP15\Custom" /copyall "C:\Program Files (x86)\WP\Custom Templates"
Regedit.exe /s \\server\soft\WPX5\Custom\Migrate.reg
Also, how do I remove the symbolic link after the install is completed?
PUSHD and POPD should help in your case.
#echo off
:: Create a temporary drive letter mapped to your UNC root location
:: and effectively CD to that location
pushd \\server\soft
:: Do your work
WP15\setup.exe
robocopy.exe "WP15\Custom" /copyall "C:\Program Files (x86)\WP\Custom Templates"
Regedit.exe /s WPX5\Custom\Migrate.reg
:: Remove the temporary drive letter and return to your original location
popd
Type PUSHD /? from the command line for more information.
I feel cls is the best answer. It hides the UNC message before anyone can see it. I combined it with a #pushd %~dp0 right after so that it would seem like opening the script and map the location in one step, thus preventing further UNC issues.
cls
#pushd %~dp0
:::::::::::::::::::
:: your script code here
:::::::::::::::::::
#popd
Notes:
pushd will change your working directory to the scripts location in the new mapped drive.
popd at the end, to clean up the mapped drive.
There's a registry setting to avoid this security check (use it at your own risks, though):
Under the registry path
HKEY_CURRENT_USER
\Software
\Microsoft
\Command Processor
add the value DisableUNCCheck REG_DWORD and set the value to 0 x 1
(Hex).
Note:
On Windows 10 version 1803, the setting seems to be located under HKLM:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor
Basically, you can't run it from a UNC path without seeing that message.
What I usually do is just put a CLS at the top of the script so I don't have to see that message. Then, specify the full path to files in the network share that you need to use.
I needed to be able to just Windows Explorer browse through the server share, then double-click launch the batch file. #dbenham led me to an easier solution for my scenario (without the popd worries):
:: Capture UNC or mapped-drive path script was launched from
set NetPath=%~dp0
:: Assumes that setup.exe is in the same UNC path
%NetPath%setup.exe
:: Note that NetPath has a trailing backslash ("\")
robocopy.exe "%NetPath%Custom" /copyall "C:\Program Files (x86)\WP\Custom Templates"
Regedit.exe /s %NetPath%..\WPX5\Custom\Migrate.reg
:: I am not sure if WPX5 was typo, so use ".." for parent directory
set NetPath=
pause
Instead of launching the batch directly from explorer - create a shortcut to the batch and set the starting directory in the properties of the shortcut to a local path like %TEMP% or something.
To delete the symbolic link, use the rmdir command.
I ran into the same issue recently working with a batch file on a network share drive in Windows 7.
Another way that worked for me was to map the server to a drive through Windows Explorer: Tools -> Map network drive. Give it a drive letter and folder path to \yourserver. Since I work with the network share often mapping to it makes it more convenient, and it resolved the “UNC path are not supported” error.
My situation is just a little different. I'm running a batch file on startup to distribute the latest version of internal business applications.
In this situation I'm using the Windows Registry Run Key with the following string
cmd /c copy \\serverName\SharedFolder\startup7.bat %USERPROFILE% & %USERPROFILE%\startup7.bat
This runs two commands on startup in the correct sequence. First copying the batch file locally to a directory the user has permission to. Then executing the same batch file. I can create a local directory c:\InternalApps and copy all of the files from the network.
This is probably too late to solve the original poster's question but it may help someone else.
This is the RegKey I used:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor]
"DisableUNCCheck"=dword:00000001
My env windows10 2019 lts version and I add this two binray data ,fix this error
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor DisableUNCCheck value 1
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Command Processor
DisableUNCCheck value 1
This is a very old thread, but I still use Windows 7. :-)
There is one point that no one seems to have taken into account, which probably would help Windows 10 users also.
If Command Extensions are enabled, the PUSHD command accepts network paths in addition to the normal drive letter and path.
So the obvious - and simplest - answer might be to enable command extensions in the batch script, if you intend to use PUSHD. At the very least, this ought to reduce the problems you might have in using PUSHD wqith a network path.
I stumbled upon this question while searching for a solution to a specific problem. I needed to make a batch script that sits in a network folder (UNC path) with a Python script. The goal was to be able to double click on the batch script and have it run the Python script:
with the network folder containing the script as the working directory,
without modifications to the Python script (no command line parameters or hard-coded paths).
without creating another Python file.
The pushd and popd solutions were unsatisfactory. They work, but if the user were to get in the habit of forcefully terminating the script while it was running, they would end up with a bunch of mapped drives in My Computer since popd wasn't run.
I start by using cls to clear the UNC path error. I then assign the path containing the batch script to a variable. I slice the path to remove the trailing backslash (otherwise, Python throws a SyntaxError). Finally, I run a couple Python commands inside the batch file that change the working directory and execute the target script:
cls
#echo off
set pyfile=myscript.py
set batchdir=%~dp0
set wdir=%batchdir:~0,-1%
python -c "import os; import runpy; os.chdir(r""%wdir%""); runpy.run_path(r""%pyfile%"")"
pause
Editing Windows registries is not worth it and not safe, use Map network drive and load the network share as if it's loaded from one of your local drives.

What configuration file sets $DISPLAY in Leopard?

According to this, for best results in Leopard my $DISPLAY variable should start with /tmp/launchd. Alas, my $DISPLAY variable is /tmp/launch-aLhnOW/:0
I do not set $DISPLAY in any of these ...
/private/etc/profile
/private/etc/bashrc
~/.bash_profile
~/.profile
... so I suspect there is some other configuration file that X11 is reading. Any suggestions?
I specifically need to ensure that it is not set anywhere. Per the linked article:
Starting X11.app from the dock will get you two icons, setting it to auto-launch is also a no-no, and if you have set DISPLAY in any of your configuration files you get a disaster.
I think your DISPLAY variable looks all right. I don't think it is being set by a configuration file.
Normally you have a launchd configuration file such as /System/Library/LaunchAgents/org.x.startx.plist. This contains a section:
<key>Sockets</key>
<dict>
<key>:0</key>
<dict>
<key>SecureSocketWithKey</key>
<string>DISPLAY</string>
</dict>
</dict>
I believe this causes launchd to open a socket and set the DISPLAY variable to its path. When a program contacts this socket, startx is invoked by launchd.
You should be able to set it in the ~/.MacOSX/environment.plist file. Details can be found here.

Resources