Paths to do-file in Stata - stata

Would it be possible, when I launch a do-file to recover the path of the do-file as a variable?
I'm sharing a project with a co-author (via Dropbox). The structure of the folders (data, logs, etc.) is therefore the same on both sides.
But the folders are situated differented on my coauthor's filesystem and mine. It would therefore be helpful for us to write do-file that are agnostic about the path of the folders, etc.
We would like the path to our projects not to be hard-coded.
Thank you!

You can do various things in this territory, including
Passing the name of a directory to a do-file as an argument. For example,
do mydo d:/myproject/data1812
launches the file mydo.do and passes the argument of a particular directory to the do-file. Inside the do-file you can grab the argument as
local myfolder "`1'"
i.e. the thing passed is passed as local macro 1. (Any other arguments would be local macros 2, 3, etc.)
Make sure your references to locations generally and files in particular are relative within the do-file and run the do-file from the parent directory.
Use global macros within your main do-file for locations and then re-define them within a master do-file which you run first.
Notes: It's best to use forward slashes, even under Windows; Stata will translate. Also, if there are embedded spaces, bind the whole thing in double quotes.
do mydo "d:/my project/data1812"
The second seems closest to your preference for not wiring in particular locations. But if you are using files from different places you have to tell Stata somehow where they are....

Nick's comment above gives the answer: c(pwd). This gives you a relative starting point for later commands, e.g. opening a dataset in the data folder:
use `c(pwd)'/data/yourdata, clear
Your problem might be that double-clicking a do-file does not cause Stata to set the working directory to its folder (while it does for datasets, which is inconsistent and not necessarily helpful).
There is no particular solution to that issue, except perhaps by writing your project folder path into a global macro set at startup by your profile.do file in your Stata application folder.
I teach classes of students and have them set their working directory with such a system. It works alright.

Paths to do-file in Stata
Several years has passed but the answer is still the same: there is no direct way to determine the location of a current do-file. The discussion around this topic has been raised many times on the Statalist. You can find plenty of useful tips here (just a brief overview, more discussion on the Statalist):
https://www.stata.com/statalist/archive/2007-09/msg00156.html
https://www.stata.com/statalist/archive/2013-07/msg00664.html
https://www.statalist.org/forums/forum/general-stata-discussion/general/1378783-do-i-have-to-specify-a-directory
In addition to those and Nick Cox and Fr. answers, I propose my humble solution to a collaborative work in Stata (that works on different machines both on Windows and Linux). It does not require additional modules and depends only on how you organize your materials in folders.
Tip 1. cd to your working directory with a hint -cap- and keep the -cd- code in the beginning of a do-file:
cap cd "W:\Bonds\" //Collaborator 1
cap cd "C:\Users\StataUser\Desktop\ProjectForBonds\" //Collaborator 2
cap cd "/media/DATA/work_materials/Dropbox/MyProjects/Bonds/" //Collaborator 3: Linux machine
cap cd "D:/work_materials/Dropbox/MyProjects/Bonds/" //Collaborator 3: PC
cap cd "E:/Projects/Dropbox/MyProjects/Bonds/" //Collaborator 3: Laptop
-cap- evades possible errors if a directory does not exist, so every user will get to his own working directory of the project. After -cd-ing to that directory you can save the path as a global variable and use it further in the code (if that is necessary):
global cdpath = "`c(pwd)'"
di "$cdpath" //show current folder
di `"{browse `"$cdpath"':Current folder}"' //optional: click to open the folder in the explorer
Hint: as Nick Cox mentioned, use "/" instead of "\". When you combine "\" with global/local variables, Stata treats this as a combination with an escape symbol (to be able to use symbols like ` and $ in strings), so using "\" may corrupt your browsing strategy. Check it via this code:
global cdpath = "`c(pwd)'"
di "$cdpath"
local i = 1
cap noi use "$cdpath\`i'\auto", clear
cap noi use "$cdpath/`i'/auto", clear
Tip 2. Keep the same folder structure by creating directories within Stata:
cap mkdir "./Temp"
cap mkdir "./Graphs"
Where "." means the current working directory. So you create "Temp" and "Graphs" folders inside the working directory. There you can store your temporary datasets, place graphs, etc.
You don't need to worry if a directory exists: -cap- alleviates this issue.
Tip 3. When saving/opening/deleting files (data, graphs, logs, etc.) explicitly tell Stata to use the relative paths:
use "./SourceData", clear
graph export "./Graphs/RollingBond.png", as(png) replace
save "./Temp/Years.dta", replace
save "./FinalBond.dta", replace
cap erase "./Temp/Years.dta"
Stata will know that you are still in your root folder and work relative to that folder.
And of course you can write full paths like this:
save "$cdpath/Temp/FinalBond.dta", replace
These tips work on both Windows and Unix and only requires to write for a new user the -cap cd "..."-. Very useful when you or your collaborator work from a thumbdrive and don't have access to any other place on a computer.

Related

Is there a way to apply SAS EG processes to new files?

I'm taking over a project from a coworker that involves several extensive SAS process flows. I have all the files with all the same names and a copy of the process flows they used. Since the file paths in their processes are direct references to their computer, normally I would just re-import the files with the same output names and run the process from there. In a few cases I would have to recreate a query builder as I'm using a few .sas7bdat files from another project.
However, there are quite a few files involved and I may end up having to pass this to another coworker in a few months, and since I can't get a good look at exactly what the import task is doing I'm concerned I may have some of the variables imported incorrectly. Is there an easy way to just change the file path the import or other task refers to?
Given the updates in comments, there's two possibilities I see.
If the paths you're changing are, or can be, relative to the location of the EGP, then you can right click on the Project->Properties->File References and check "Use paths relative to the project...", which means instead of storing a file in c:\my EGP folder\my code folder\code.sas it would store it as my code folder\code.sas. So then if the whole project moves to another computer (or just any other folder) then it automatically has the right path. This is mostly useful for code or similar things.
Otherwise, you're going to have to convert things to SAS code modules. There you can use macro variables to define the locations of things.

Linked directory not found

I have following scenario:
The main software I wrote uses a database created by a simulator. This database is around 10 GB big at the moment, so I want to keep only one copy of that data per system.
Assuming I have following projects:
Main Software using the data, located at /SimData
DLL using the data for debugging, searching for data at /SimData
Debugging tool to parse the image database, searching for the data at /SimData
Since I do not want to have all those programs have their own copy of SimData (not only to decrease place used, but also to ensure that all Simulation data used is always up to date for all programs).
I created for the DLL and Debugging Utility a link named SimData to MainSoftware/SimData, but when opening a file with "SimData\MyFile.data" it cannot find it, only the MainSoftware with the ACTUAL SimData folder can find it.
How can I use the MainSoftware/SimData folder without setting absolute paths?
This is on Windows 7 x64
I agree with Peter about adding the DB location as a configurable parameter. A common place to store that is in the registry.
however, If you want to create links that will be recognized by your software, try hardlinks. . fsutil should do the trick as described here.
You need a way to configure the database location. You could use an INI or other configuration file, or a registry setting, or a command-line input, or an environment variable. Or You could write your program to search a directory hierarchy... for example, if the various modules are usually siblings of each other in your directory tree, you could search for SimData/MyFile.data, ../SimData/MyFile.data, ../../MainSoftware/SimData/Myfile.data, and use the first one found.
Which answer is the "right one" depends on your situation.

Running cmd commands in C++

I am trying to make a text adventure based on C++. I have made folders which contains the specific files to each path. Suppose I go south from a room, i need to go into a folder named "south". I am having problems here as I don't know how to change directory like "cd .\south" in C++. Please tell me how to change directory in C++.
I tried to use:
system("cd .\\south")
but it does not change directory. I also searched on Google but it gives link to another function called "ShellExecute" which I don't know how to use. Please help (I am a complete beginner).
The system function create a new process for the command. This means that any directory changing will be local to that new process.
You want the _chdir function instead:
_chdir("south");
Alternatively you can use the WIN32 function SetCurrentDirectory.
Note: _chdir is the Windows CRT function name, on POSIX systems (like Linux or OSX) it's chdir (without the leading underscore).
Direction 1:
Simply What you have to do is change the current directory. for this read this article
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363806(v=vs.85).aspx
But if your application is multi threaded. then you need to be careful. because current directory is common for the whole application so other thread may change the applications current directory.
Direction 2:
If you need to do this by executing system command (I don't know weather it is possible). then you can execute multiple system command using && in windows environment.
EG: system("cls && date && pause");
The problem is that each system command will be executed in separated processes, so your cdcommand will work but won't be effective for the next commands.
You could use chdir if you're on a Linux/Unix system or SetCurrentDirectory for Win32 API but i'm not sure whether it's actually what you want to do.
The answer to the specific question you are doing have already being given. However, I wonder why you are trying to change the current directory in order to answer to a command given by the user.
Maybe you are doing it this way because you want to gain knwoledge something specific, however, take into account that the average way to face a text adventure is not to create folders in the computer, but to create the appropriate structures.
You should have classes at least for: Location, Object, Character
You should have vector of locations and objects in order to represent all possible locations and objects in the game.
The playing character should also have a list of objects that he is able to carry with him (thogh you can make that extensible to other characters in the game).
Each location should have a: name, description, and a vector of ten positions for the common exits, such as north, south, east, west, ne, nw, se, sw, up and down. Inside that vector, you could store the number of the Location to go when that exit is chosen.
And finally, you need to parse the input of the player, in order for the game to be able to understand the commands.
This of course, are the minimums of the adventure.
You can use already existing systems, such as Inform, though again I don't know if you are trying to exercise your C++ skills.
Remember you can look for the help of true experts in adventures by visiting the interactive fiction forum:
http://www.intfiction.org/forum/

Recycle Bin items shredding

I'd like to shred the recycle bin data, but I don't know which is the best approach, so it goes:
- In windows vista and 7 the files are renamed starting with $R and a bunch of random chars and also a file starting with $I and the same random chars is created, this file contains some info about the file, including it's name. The $Recycler.bin directory also contains a Desktop.ini, I don't know what it does.
- In below vista the management of the recycled files is done using hidden INFO2 files, which do the association between random file name and real name.
Now, let's say I want to build an app that can run on both below and above vista systems, what common strategy would you use? My first lead woud be to navigate the namespace, get the absolute path to the Recycler directories ovewrite the data within the files and delete them manually from the Recycler directories. I also need to notify the shell afterwards.
What other approaches would you use?
*Correct me if I'm wrong in the above statements.
sources: Here and here
How about using IShellFolder interface?
LPITEMIDLIST pidlRecycleBin = NULL;
SHGetSpecialFolderLocation (m_hWnd, CSIDL_BITBUCKET, &pidlRecycleBin);
[...]

finding my py modules in sub folders, from the main application working dir

this question might have been asked before, but I could not find it.
I am on a Linux box. I have py app that runs from a folder called /avt. (example)
I did not write this code, and it has about 12 modules that go with it. I was the lucky engineer to inherit this mess.
this app imports other modules that live under this dir /avt/bin
I want to be able find my modules in the /bin dir no matter where the current working dir is. sometimes the app changes dir to some other sub folders to perform some file I/O. Then should return, but seems like sometimes it does not make it back, because the code will error out with "no such file or directory" error. so I want to test for working dir each time before I do any file I/O to the /bin dir.
As an example, I want to create files in /bin, and then later open those files and read data from them. How can I test to make sure my current working dir is always /avt? and if it is not, then ch.dir to it? Note: it also has to be portable code meaning if must run on any directory structure on any Linux machine.
I tried this code, but it is not very clean I think. Python is not my main language. Is this coding proper and will it work for this? forgive me I don't know how to format it for this forum.
Avtfolder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
if Avtfolder not in sys.path:
sys.path.insert(0, Avtfolder)
if Avtfolder.__contains__('/avt'):
modfilespath = Avtfolder + '/bin'
print 'bin dir is ' + modfilespath
else:
print 'directory lost...'
#write some code here that changes to the root /avt dir
I have a few notes.
First, I'm afraid you are mixing up two problems (or I couldn't tell from the question which one you're facing). These problems are:
I/O to files that can reside in different directories on different machines
Importing Python modules used by your app that can also be in slightly different locations.
The title of the question and some of the text suggests you're dealing with problem 2, whereas references to I/O and "no such file or directory" error point to problem 1.
Those are, however, separate problems and are treated separately. I won't be able to give the exact recipes on both, but here are some suggestions:
For problem 1: I don't think it's a good idea to do some I/O, create files, etc. in the folder where the user installs the Python libraries. It's a folder for Python modules, not data. Also, if the library is installed via setup.py, using pip or easy_install (if it isn't the case now, that can change in the future) then the program will probably habe insufficient permissions to write there, unless invoked as root. And that's right. Create files somewhere else.
As to "how to track the directory changes" part: I must confess I don't quite understand what you mean. Why do you even using the concept of "current directory"? In my mind you should just have some variable such as write_path, data_path, etc. and the code would be
data = open(os.path.join(data_path, 'data.foo'))
dump = open(os.path.join(write_path, 'dump.bar'), 'w')
etc.
Why do you even care where are your libraries located? I don't think it's right, I'd change that. This inspect.currentframe() stuff smells like you really need to rethink the design of the library.
Now, what the location of the libraries matters for is Problem 2. But again, the absolute path shouldn't matter (if it does, change that!). You only need all the modules to be inside one folder (or its subfolders). If they are in the same folder, you're good. import foo will just work. If some are in subfolders, those subfolders should have a file named __init__.py in them, and then they will be seen as modules by Python interpreter, so you'll be able to do from foo import bar, where foo is a subfolder with __init__.py and bar.py in it.
So, try to rewrite it so that you don't depend on where the .py files are. You really shouldn't need to use inspect there at all. On another note, don't use special methods like __contains__ directly unless you really need to. if '/avt' in Avtfolder will do the same.