In Ruby on Windows 7, how do you open a program's source file from the command line?
Example:
def dev_mode
if ARGV[0] == '--dev-mode'
system('open test.rb')
end
end
Is it possible to open a program using the default editor of the user's computer? Such as opening it in notepad (if the user doesn't have an editor) or the editor the user uses for source files?
The canonical way to open a file with the associated program is different from one operating system (or shell) to another. Here are 4 examples that will work on the specified OSes:
Opening the File
Windows
Use the standard command shell start, available beginning with Windows 95:
system %{cmd /c "start #{file_to_open}"}
Mac OS X
Use the standard open command:
system %{open "#{file_to_open}"}
Linux/Unix Gnome
Use the Gnome utility gnome-open:
system %{gnome-open "#{file_to_open}"}
Linux/Unix
Use the xdg-open utility:
system %{xdg-open "#{file_to_open}"}
Associated Programs
Detecting the associated program for a file type can be a fairly tall order on any one system. For instance, with Windows, you have to inspect the registry, whereas with Mac OS X you have to read the right plist values; Linux is a whole other world, altogether.
You're likely better off simply requiring the user to have a program associated to make things easy enough to get started. Once you have the other logic working in your application, you might be able to add interesting features like fallback to a default application in the absence of an existing file association.
On a Mac, you're already halfway there; open opens a file in the default application. By default it opens a reasonable editor for text files and XCode for Ruby files; I don't edit Ruby in XCode, but I could change the association if I wanted.
The name of the file that started a Ruby program is in $PROGRAM_NAME, so you can do
def dev_mode
if ARGV[0] == '--dev-mode'
system("open #{$PROGRAM_NAME}")
end
end
On Unix-like systems, including OS X, you might want to use the value of ENV['EDITOR'] (the EDITOR environment variable) if it's set. That's a convention used by many programs.
I'll let others give answers for other operating systems.
Related
My question is not about how to run the scripts with double click!
I'm curious about the reason of such behavior.
The .bat, .cmd, .vbs, .exe, and many others runs with the double-click, but .ps1 not, why?
The reason to associate .ps1 with Notepad is about security.
Back in the days, Microsoft got burned really bad because of associations' default actions. Per default, Windows' file manager (later known as File Explorer) aimed at easy usage. It didn't show file extensions. That is, MyResume.doc was shown in the default Explorer list as simply MyResume - and it often had a Word icon too.
While this was convenient a way to save screen real estate, it offered a wonderful way to exploit systems. A lot of users simply double-clicked files based on their names and icons. Now, crackers started to send around files that had double extension like MyResume.doc.vbs. Explorer's default action was to strip the .vbs, which meant that the file actually was Visual Basic Scripting file. Since Windows associated .vbs to Windows Scripting Host, the script file was executed with user permissions. To prevent this attack vector, Powershell files are not associated with powershell.exe per default.
Famous cases of extension exploits are the love letter ILOVEYOU and promise of adult content about Anna Kournikova.
Another can of worms (sorry for the horrible pun) are Windows screen saver files. The .scr files are really just executables. A lot of users were fooled to install backdoors to systems, as they didn't understand risks of installing screensavers. This was further exploited by sending files that had extensions not matching the payload, and relying that OS still picked the proper application association.
I've hooked the system call to typedef int (*orig_open_f_type)(const char *__file, int __oflag, ...); and thus, whenever a file gets opened, my code gets the event before it is passed on to the system. I created a dynamic library that overrides the open call and inject this library using DYLD_INSERT_LIBRARIES - working on a Mac machine and using XCode. It is a standard step that enables me to hook calls.
Now, I have bash script in which I have some files that I want to open. I have tried xdg-open , cat, exec - but they are not triggering the system call to open the file.
How should I invoke this open call in my bash script?
Please note that I have tested my open call hook, by opening files in C code.
I believe you're running foul of Apple's SIP (System Integrity Protection) which is designed to stop people doing things like that with system-provided executables. SIP was added to Mac OS X El Capitan (10.11) and continues in macOS Sierra (10.12).
To demonstrate whether this is the problem, consider copying /bin/cat to /usr/local/bin/cat and then try hooking (running) the local copy. You might get away with it there. This 'workaround' is purely for demonstration purposes. Basically, if I'm right, SIP is Apple's way of saying "don't go messing with our software".
You can follow links from Can Mac OS X El Capitan run software compiled for Yosemite that expects libraries in /usr/gnu/lib? to find out more about SIP. Following links via What is the "rootless" feature in El Capitan, really? on Ask Different to a blog article on System Integrity Protection, it says explicitly:
Runtime protection
SIP’s protections are not limited to protecting the system from filesystem changes. There are also system calls which are now restricted in their functionality.
task_for_pid() / processor_set_tasks() fail with EPERM
Mach special ports are reset on exec(2)
dyld environment variables are ignored
DTrace probes unavailable
However, SIP does not block inspection by the developer of their own applications while they’re being developed. Xcode’s tools will continue to allow apps to be inspected and debugged during the development process.
For more details on this, I recommend taking a look at Apple’s developer documentation for SIP.
Emphasis added
Basically, this means that you won't be able to hook calls to the open() system call for Apple-supplied software installed in the system directories. You will need to rethink what you are trying to do.
Running any normal command -- like cat -- that processes a file will cause the file to be opened. You can also open a file (and immediately close it) using the shell syntax:
: < /path/to/file
If your system call hook isn't getting called, something must be wrong with your hook -- there's no way these commands are working without opening the file. Alas, you haven't explained how you implemented your hook, so we have no way of debugging that.
The file command opens the file to look at its contents.
$ file /path/to/file
I have suggested this because it eventually leads to having the system call open which can be confirmed using strace.
$ strace file /path/to/file 2>&1 | grep open
I thought one of the good things about using file is that it opens the file in read only mode. In comparison to other ideas, unlike cat, it will not have to run through the entire file, just part of it, so the time complexity using file may be constant. Unlike vim, which someone has suggested, file will return when finished and not block like a text editor would.
I have set up shuffle_play.rb in Ruby by Example to work on Windows, with mpg123 instead of ogg123. The critical part is a method called play_file, which initially I wrote like this
def play_file(file)
system("mpg123 \"#{file}\"")
end
I have mpg123 in the same directory as my script ... it didn't work. But this does work:
def play_file(file)
system("mpg123.exe \"#{file}\"")
end
I reckon it's because I don't have working directory in %PATH% (and indeed the problem goes away when I add it) but even then I don't know enough about Windows to know the difference. Could someone explain the rationale for this?
Probably the examples assume that you're on a *nix variant such as Linux or Mac. In those Operating Systems, the program is called mpg123, because those OS, don't care about extensions, the just check that the file has an executable attribute
On windows things are very different. Windows decides if something is a program depending on the extension (.exe, .com, .bat, .cmd, etc.). So the program in windows has to be called mpg123.exe. If you open a command line on windows, you can run the program without specifying the extension, as windows automatically tries the different extensions. This behaviour of trying different extensions happens ONLY in the command line and not when you try to invoke a program from another one.
There a environment variable called PATHEXT that list in which order windows tries the different extensions. On my computer that list is:
C:\Windows\System32>echo %PATHEXT%
.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.RB;.RBW
I hope it was clear. And a suggestion if you want to code in ruby, install Linux or get a Mac.
Hey there, I'm building a remote shell server that interfaces between a text-only client and a virtual shell.
It works perfectly when using regular shell commands, but the first thing that people try after that is vim, which promptly drives my server crazy and can't even be closed remotely.
Is there any way to detect ncurses based programs and prevent them from running in my special shell?
(the server is ruby, but any system command will do)
You can declare the capabilities your shell has, by setting the TERM environment variable to the correct value. For instance, if your shell has the same capabilities as the vt100 terminal, export TERM to the correct value, and programs like vim will respect that.
To run vim in vt100-mode, try:
TERM=vt100 vim
You could also try:
export TERM=dumb
The trick is to find a terminal that corresponds to the capabilities of what you are creating. There is a lot to choose from. On my system (Arch Linux) this gives me a long list of choices:
find /usr/share/terminfo
You might be able to find a terminal specification that corresponds to what your program can handle.
Alternatively, you may want to consider implementing terminal emulation for ansi or vt100:
http://en.wikipedia.org/wiki/ANSI_escape_code
http://www.termsys.demon.co.uk/vtansi.htm
Best of luck!
I have a build script where i create a text report file and output various log type stuff to it. The data is all being built onto an external hd which (according to 'mount') has file format "fuseblk" (which i've never heard of).
The building all seems to work ok but my report files are being saved as executables, which linux interprets as SOR files. I'd like them to just be regular text files, openable by default in my regular text editor.
I'm making the file, and writing to it, like this:
#report = File.open(File.join(DESTINATION_BUILD_FOLDER, "#{title.folder_name}_report.txt"),"w")
...
s = "making modules folder inside resource_library folder";puts s; #report.puts s
...
#report.close
I've done this lots of times before and never encountered this problem. Any ideas anyone?
cheers, max
ps i know that i can edit the saved files to make them non-executable, my question is 'why is this happening in the first place?'. Cheers :)
I don't think there's anything wrong with your program. The fuseblk just means it's being mounted through FUSE, which allows filesystem drivers to run as userspace programs, instead of kernel modules. Most likely, the filesystem is NTFS or FAT32.
The problem here is that Linux is assuming everything on the drive has the execute bit set. This is because neither NTFS nor FAT32 have the capability to store Linux permission bits (NTFS has a very different permissions system, FAT32 has virtually none). And I bet you're trying to double-click on the log files in something like the gnome file explorer, right?
Well, go there with the command line and use less or your favorite command-line editor to view them. Or right click on them in the file explorer, or open them with File -> Open from a text editor. If you ask your question to people who know Gnome (or KDE?) better, you'll probably get a better answer.