And the cowwwwws went homeeeeeeee Or did theyyyy 如果要去除重复字符或将其压缩在一起,可以使用-s选项,因为都是字母,故使用[a-z]: $tr -s "[a-z]"<cops.txt And the cows went home Or did they
12.4 删除空行
可使用-s来作这项工作.换行的八进制表示位\012,例: $more plane.txt and 0500 399999 2773888
Gnome uses C, which is much easier for programming newbie as me. But there are a lot of bindings like Gtkmm for C++. When you are confident for high quality Object-oriented programming, you can think about moving away to other platform or X windows. While KDE uses C++, to start learning programming with this platform, in my mind is not good idea.
Gnome if totally free with GPL. KDE's base is QT, which is free on Linux, but not for all the OS, such as MS Windows. So the troubles maybe are not far from you, especially when you want to do some commercial project programming with QT, at that time, maybe it's a little bit late to convert to Gnome. And also this problem make a lot of vendors keep away from it.
Maybe the reason in 2), Gnome has a lot of supports and sponsors like IBM, Redhat, Sun. They can do whatever they like without any worry about legal issues. So with their supports and sponsors Gnome is growing much better and faster. As users and developers working in such a platform will benefit all the time, almost no worries about out of date or using or learning something without future.
KDE is much like Windows, both the appearance and integration with embedded programs. I don't like windows environment in this way. Gnome is much better, almost nothing embedded compared to KDE, that's true that KDE brings a large mount of programs. But what Gnome provides is the stable and highly extensive base platform. I think this is why some many big companies like it, they can develop their own programs to attract users, for instance, Mozilla's Firefox, Sun's OpenOffice. Gnome is working as a free medias to put advertisements on it. This should be the proper way of how the media platform should work in, just like some many free newspapers in London.
For my own favorite, I like Ubuntu, but Kubuntu are not so friendly and bring me a lot of debugging issues, such as gnome-system-monitor, Knetworkmanager and Kwallet always work improperly. So, just to use the default desktop environment is always right.
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } }
The simple Java source code in Listing 1 can be compiled into Java bytecode with gcj -C HelloWorld.java and interpreted using gij HelloWorld. The same source code can be compiled into a native executable using gcj --main=HelloWorld -o HelloWorld HelloWorld.java and executed using ./HelloWorld. This article avoids including import and other trivial statements in Java code listings; see Resources for the full source files.
####################
## make executable $ gcj -C HelloWorld.java $ gij HelloWorld # to test if it works $ gcj --main=HelloWorld -o HelloWorld HelloWorld.java $ ./HelloWorld # to run it and test
## make executable jar (same way with in Windows) $ gcj -c HelloWorld.class # compile Hello.class to Hello.o $ jar cvf hi.jar HelloWorld.class # create a jar ## You got to include "manefest" file containing the class name of the "main()" method as:Main-class: your.package.Class_NAME.without_dot_class # modify the "MANIFEST.MF", adding at the end: Main-class: HelloWorld # Note: 1) there is a space after ':'. 2) there is NO empty line before the 'Main-class' line.
## make executable with jar $ gcj -c HelloWorld.class # compile Hello.class to Hello.o $ jar cvf hi.jar HelloWorld.class # create a jar $ gcj -c hi.jar # compile hi.jar to hi.o $ gcj --main=HelloWorld -o hi hi.o # link hi.o to hi; gcj accept all reasonable input files, such as .java files, .class files and .o files, even .jar files. Super!!! $ ./hi # run hi Hello, World!
5. ifconfig (to check whether get the IP properly or not) ping somewhere to test P.S. Note: the networkmanager looks do not change at all. Because it did nothing, and not reflect the status of the network.
Nokia took another long step today with the N810, the third generation of its ‘Internet tablet’ line which began with the launch of the N770 in November 2005 and was followed by the N800 in January this year.
Like its predecessors, the N810 is powered by Nokia’s own Internet Tablet OS, also known as Maemo. This open source build is based on Debian and is topped by the same ‘Hildon’ user interface layer as will be featured on the Ubuntu Mobile OS used by Intel’s mobile Internet devices around the middle of 2008. The N810 runs the latest Internet Tablet OS 2008 release, aka Maemo 4.0 ‘Chinook’.
2GB internal storage (not including memory cards), ships with maps for use with GPS
The code names of Debian releases are names of characters from the film Toy Story. The unstable, development distribution is nicknamed sid, after the emotionally unstable next-door neighbour boy who destroyed toys on a regular basis.
Where do these codenames come from?
So far they have been characters taken from the movie "Toy Story" by Pixar.
buzz (Buzz Lightyear) was the spaceman,
rex was the tyrannosaurus,
bo (Bo Peep) was the girl who took care of the sheep,
hamm was the piggy bank,
slink (Slinky Dog (R)) was the toy dog,
potato was, of course, Mr. Potato (R),
woody was the cowboy,
sarge was the sergeant of the Green Plastic Army Men,
etch was the toy blackboard (Etch-a-Sketch (R)),
lenny was the binoculars.
sid was the boy next door who destroyed toys.
Sid repository is dangerous, but it's really powerful for developers. Almost you can find any lib packages here. #################################### deb http://ftp.de.debian.org/debian sid main ## #################################### the gpg key: when you run apt-get update, you will be told error about gpg key:A70DAF536070D3A1 run: ####################################
Sometime when you install some new package, it will remove all its conflict packages, before this, you will be notified. But most of the people like me don't want to read all of the long-winded words every time. So sooner or later you will make such mistake.
Yes, I did. when I install some package about pulseaudio, which comes with Fedora 8 next week, one of the plugins conflicts with the current system sound server, so it removed the esound server and all relative packages (including all the Gnome and Kde package). I can not log in the X windows environment.
########################################
Here are the solution: 1. a. find the synaptic history log files, which are stored in /root/.synaptic/log/, sorted by date. You can not use 'cd' to browse the folder, so you must use 'ls' and 'cp' to get the file. b. remove some contents of the file, just leave the removed packages. c-1. using vi, input such command when you click':', '1,$j'. Here j can make all the lines in the file into 1 line. c-2. (another method) tr -c "[a-z][A-Z]" " " < thefile d. At the beginning of the file, add 'sudo apt-get install -y'. Here 'y' force every installation continue without prompt. e. sh+the file. everything start. when it finished. your system recovered.
2. at step 1.c. using 'sed' to add 'sudo apt-get install -y' before each line. it works, but two slow and a lot of repeat work by computer.
nice (IPA pronunciation: /naɪs/) is a command found on UNIX and other POSIX-like operating systems such as Linux. nice directly maps to a kernel call of the same name. For a given process, it changes the priority in the kernel's scheduler. A nice value of −20 is the highest priority and 19 is the lowest priority. The default nice value for processes is inherited by its parent process, usually 0.
Nice becomes useful when several processes are demanding more resources than the CPU can provide. In this state, a higher priority process will get a larger chunk of the CPU time than a lower priority process. If the CPU can deliver more resources than the processes are requesting, then even the lowest priority process can get up to 99% of the CPU. Only the superuser (root) may set the nice value to a smaller (higher priority) value.
There is also a renice command, which is used to change the priority of a process that's already running.
The exact mathematical effect of setting a particular niceness value for a process depends on the details of how the scheduler is designed on that implementation of UNIX. A particular operating system's scheduler will also have various heuristics built into it, e.g., to favor processes that are mostly I/O-bound over processes that are CPU-bound. As a simple example, when two otherwise identical CPU-bound processes are running simultaneously on a single-CPU Linux system, each one's share of the CPU time will be proportional to 20-p, where p is the process's priority. Thus a process run with nice +15 will receive 1/4 of the CPU time allocated to a normal-priority process: (20-15)/(20-0)=1/4. On the BSD 4.x scheduler, on the other hand, the ratio in the same example is more like ten to one.
A lot of people made good points in the comments section of my last posting (Understanding memory usage on Linux). Here are some of the general ideas that were mentioned:
(1) Several comments noted that non-x86 hardware has a different approach to shared memory between processes. This is true; some architectures do not handle shared memory in the same way as x86. To be honest, I don't know which platforms those are, so I'm not going to even try to list them. Thus, my previous post should be taken with a big grain of salt if you're working on a non-x86 platform.
(2) Many people also noted that this shared library feature of Linux isn't some fancy new thing, which is completely true. Microsoft Windows platforms undoubtedly have the same basic sharing feature, just like any full-featured modern operating system. My post only addressed Linux because, to be honest, I'm a Linux-centric kind of person.
(3) Yes, I did commit the sin of using "it's" instead of "its". To all of the English majors in the audience, I offer my most sincere apology.
(4) A few comments mentioned the memory size of Firefox. I must admit that I began this article with Firefox instead of KEdit as the primary example, but I was forced to switch to KEdit when I saw how big Firefox's private/writeable size was; KEdit illustrated my point much better. :)
(5) If the word "marginal" that I used confused anyone, then feel free to just mentally replace it with the word "incremental".
Thanks to everyone that commented on the posting; part of my reason for writing it was to see what other people thought, as other people usually know more than I do about any given subject.
This entry is for those people who have ever wondered, "Why the hell is a simple KDE text editor taking up 25 megabytes of memory?" Many people are led to believe that many Linux applications, especially KDE or Gnome programs, are "bloated" based solely upon what tools like ps report. While this may or may not be true, depending on the program, it is not generally true -- many programs are much more memory efficient than they seem.
What ps reports The ps tool can output various pieces of information about a process, such as its process id, current running state, and resource utilization. Two of the possible outputs are VSZ and RSS, which stand for "virtual set size" and "resident set size", which are commonly used by geeks around the world to see how much memory processes are taking up.
For example, here is the output of ps aux for KEdit on my computer:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND dbunker 3468 0.0 2.7 25400 14452 ? S 20:19 0:00 kdeinit: kedit
According to ps, KEdit has a virtual size of about 25 megabytes and a resident size of about 14 megabytes (both numbers above are reported in kilobytes). It seems that most people like to randomly choose to accept one number or the other as representing the real memory usage of a process. I'm not going to explain the difference between VSZ and RSS right now but, needless to say, this is the wrong approach; neither number is an accurate picture of what the memory cost of running KEdit is.
Why ps is "wrong" Depending on how you look at it, ps is not reporting the real memory usage of processes. What it is really doing is showing how much real memory each process would take up if it were the only process running. Of course, a typical Linux machine has several dozen processes running at any given time, which means that the VSZ and RSS numbers reported by ps are almost definitely "wrong". In order to understand why, it is necessary to learn how Linux handles shared libraries in programs.
Most major programs on Linux use shared libraries to facilitate certain functionality. For example, a KDE text editing program will use several KDE shared libraries (to allow for interaction with other KDE components), several X libraries (to allow it to display images and copy and pasting), and several general system libraries (to allow it to perform basic operations). Many of these shared libraries, especially commonly used ones like libc, are used by many of the programs running on a Linux system. Due to this sharing, Linux is able to use a great trick: it will load a single copy of the shared libraries into memory and use that one copy for every program that references it.
For better or worse, many tools don't care very much about this very common trick; they simply report how much memory a process uses, regardless of whether that memory is shared with other processes as well. Two programs could therefore use a large shared library and yet have its size count towards both of their memory usage totals; the library is being double-counted, which can be very misleading if you don't know what is going on.
Unfortunately, a perfect representation of process memory usage isn't easy to obtain. Not only do you need to understand how the system really works, but you need to decide how you want to deal with some hard questions. Should a shared library that is only needed for one process be counted in that process's memory usage? If a shared library is used my multiple processes, should its memory usage be evenly distributed among the different processes, or just ignored? There isn't a hard and fast rule here; you might have different answers depending on the situation you're facing. It's easy to see why ps doesn't try harder to report "correct" memory usage totals, given the ambiguity.
Seeing a process's memory map Enough talk; let's see what the situation is with that "huge" KEdit process. To see what KEdit's memory looks like, we'll use the pmap program (with the -d flag):
I cut out a lot of the output; the rest is similar to what is shown. Even without the complete output, we can see some very interesting things. One important thing to note about the output is that each shared library is listed twice; once for its code segment and once for its data segment. The code segments have a mode of "r-x--", while the data is set to "rw---". The Kbytes, Mode, and Mapping columns are the only ones we will care about, as the rest are unimportant to the discussion.
If you go through the output, you will find that the lines with the largest Kbytes number are usually the code segments of the included shared libraries (the ones that start with "lib" are the shared libraries). What is great about that is that they are the ones that can be shared between processes. If you factor out all of the parts that are shared between processes, you end up with the "writeable/private" total, which is shown at the bottom of the output. This is what can be considered the incremental cost of this process, factoring out the shared libraries. Therefore, the cost to run this instance of KEdit (assuming that all of the shared libraries were already loaded) is around 2 megabytes. That is quite a different story from the 14 or 25 megabytes that ps reported.
What does it all mean? The moral of this story is that process memory usage on Linux is a complex matter; you can't just run ps and know what is going on. This is especially true when you deal with programs that create a lot of identical children processes, like Apache. ps might report that each Apache process uses 10 megabytes of memory, when the reality might be that the marginal cost of each Apache process is 1 megabyte of memory. This information becomes critial when tuning Apache's MaxClients setting, which determines how many simultaneous requests your server can handle (although see one of my past postings for another way of increasing Apache's performance).
It also shows that it pays to stick with one desktop's software as much as possible. If you run KDE for your desktop, but mostly use Gnome applications, then you are paying a large price for a lot of redundant (but different) shared libraries. By sticking to just KDE or just Gnome apps as much as possible, you reduce your overall memory usage due to the reduced marginal memory cost of running new KDE or Gnome applications, which allows Linux to use more memory for other interesting things (like the file cache, which speeds up file accesses immensely).
You can decorate your KDE very easily when you first activate it. All this is depending on the command of "kpersonalizer". Namely, when you want to change the look and feel rapidly, while not tweak hundreds of KDE options, just run it in konsole (terminal).
GNOME keyring manager stores passwords such as WEP into an encrypted format that can be used over and over again when required by the user.
Bring on Libpam-Keyring
There is hope yet! the libpam-keyring library can stop GNOME Keyring-manager prompting for a password when you access your protected wireless network. Install libpam-keyring by doing the following command in the terminal:-
sudo apt-get install libpam-keyring
Open the the gdm file:-
gksudo gedit /etc/pam.d/gdm
Add the following line to the end:-
@include common-pamkeyring
Save the file and exit. I should also point out that your GNOME Keyring-manager password MUST be the same as your log on (root). To ensure this go to the GNOME Keyring-manager at the “System > Administration” menu and delete your keyring, so nothing exists and reboot. You should now see no password prompt for your wireless network ;-).
ubuntu-restricted-extras (this one can solve mp3 and other third party stuff) amarok (this will install needed codecs for mp3:libxine,gstreamer0.10-ffmpeg)
xine(totem-xine)
nautilus-open -terminal
ndiswrapper
libpam-gnome-keyring(when the user login, make the keyringmanager unlocked)
stardict
vnc
konquer/opera
gedit-plugins(a lot of plugins for c/c++/java/latex etc.)
lyx(for latex and other formal document writing)
lynx(command-line web browser) cmus/music123(command-line music player, sometime the mcop directory is needed to be created manually by ''mkdir -p $HOME/.kde/socket-$HOSTNAME/mcop'')
##################### eclipse(+cdt,pydev)
texmaker(+texlive-latex)
build-essential gcj
firestarter(firewall management program)
Chinese
envy (for graphical cards installation) ###################### samba(smbpasswd -a user, here this user must exist in the system users database)
Ndiswrapper, a windows driver simulation for linux, in Ubuntu Gutsy seems there is a bug about automatically loaded when you did all the commands like this:
sudo apt-get install ndiswrapper sudo ndiswrapper -i XXXXX.inf #installation of the drivers sudo modprobe ndiswrapper
In Ubuntu Feisty 7.04, When you finish these commands, the light on your pcmcia wireless card will be turned on, and restart your computer, the wireless card will be loaded automatically when Ubuntu booting. But Gutsy not.
Nothing happened, unless you run:
sudo modprobe ndiswrapper
No worries, here are two methods to solve it.
1. put "ndiswrapper" in the /etc/modules.
P.S., some wireless pcmcia card using prism54 will be loaded automatically without ndiswrapper by Ubuntu, you can stop it by this:
Put "blacklist prism54" in the /etc/modprobe.d/blacklist.
2. Just run the command "sudo ndiswrapper -ma", which will write the relative module to /etc/modprobe.d/, same effect with above.
# deb cdrom:[Kubuntu 7.10 _Gutsy Gibbon_ - Release i386 (20071016.1)]/ gutsy main restricted # See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to # newer versions of the distribution.
deb http://gb.archive.ubuntu.com/ubuntu/ gutsy main restricted deb-src http://gb.archive.ubuntu.com/ubuntu/ gutsy main restricted
## Major bug fix updates produced after the final release of the ## distribution. deb http://gb.archive.ubuntu.com/ubuntu/ gutsy-updates main restricted deb-src http://gb.archive.ubuntu.com/ubuntu/ gutsy-updates main restricted
## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu ## team, and may not be under a free licence. Please satisfy yourself as to ## your rights to use the software. Also, please note that software in ## universe WILL NOT receive any review or updates from the Ubuntu security ## team. deb http://gb.archive.ubuntu.com/ubuntu/ gutsy universe deb-src http://gb.archive.ubuntu.com/ubuntu/ gutsy universe deb http://gb.archive.ubuntu.com/ubuntu/ gutsy-updates universe deb-src http://gb.archive.ubuntu.com/ubuntu/ gutsy-updates universe
## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu ## team, and may not be under a free licence. Please satisfy yourself as to ## your rights to use the software. Also, please note that software in ## multiverse WILL NOT receive any review or updates from the Ubuntu ## security team. deb http://gb.archive.ubuntu.com/ubuntu/ gutsy multiverse deb-src http://gb.archive.ubuntu.com/ubuntu/ gutsy multiverse deb http://gb.archive.ubuntu.com/ubuntu/ gutsy-updates multiverse deb-src http://gb.archive.ubuntu.com/ubuntu/ gutsy-updates multiverse
## Uncomment the following two lines to add software from the 'backports' ## repository. ## N.B. software from this repository may not have been tested as ## extensively as that contained in the main release, although it includes ## newer versions of some applications which may provide useful features. ## Also, please note that software in backports WILL NOT receive any review ## or updates from the Ubuntu security team. deb http://gb.archive.ubuntu.com/ubuntu/ gutsy-backports main restricted universe multiverse deb-src http://gb.archive.ubuntu.com/ubuntu/ gutsy-backports main restricted universe multiverse
## Uncomment the following two lines to add software from Canonical's ## 'partner' repository. This software is not part of Ubuntu, but is ## offered by Canonical and the respective vendors as a service to Ubuntu ## users. deb http://archive.canonical.com/ubuntu/ gutsy partner deb-src http://archive.canonical.com/ubuntu/ gutsy partner
deb http://security.ubuntu.com/ubuntu/ gutsy-security main restricted deb-src http://security.ubuntu.com/ubuntu/ gutsy-security main restricted deb http://security.ubuntu.com/ubuntu/ gutsy-security universe deb-src http://security.ubuntu.com/ubuntu/ gutsy-security universe deb http://security.ubuntu.com/ubuntu/ gutsy-security multiverse deb-src http://security.ubuntu.com/ubuntu/ gutsy-security multiverse ################################################# # http://medibuntu.org/ # sudo wget http://www.medibuntu.org/sources.list.d/gutsy.list -O /etc/apt/sources.list.d/medibuntu.list # the public key: # sudo wget -q http://packages.medibuntu.org/medibuntu-key.gpg -O- | sudo apt-key add - && sudo apt-get update
deb http://dl.google.com/linux/deb/ stable non-free # sudo wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - # Or goto http://www.google.com/linuxrepositories/apt.html to download the key, then install by using synaptic
# deb http://ftp.de.debian.org/debian/ sid main ## sudo gpg --keyserver wwwkeys.eu.pgp.net --recv-keys 07DC563D1F41B907 ## sudo apt-key add ~/.gnupg/pubring.gpg
The tablet — which includes no cellular connectivity, but does sport Wi-Fi and Bluetooth — is the third such device Nokia has produced in the past two years, as part of its drive to reposition the company's handsets as "multimedia computers" rather than mobile phones.
Nokia announced the tablet, which runs on the company's Maemo Linux operating system, at the Web 2.0 Summit in San Francisco.
The N810 will come with Skype and a Mozilla-based browser pre-installed and, unlike Nokia's other tablets, will come with a slide-out keyboard and integrated GPS — a feature Nokia expects will eventually feature on all its phones.
The device will ship from mid-November in some territories, for around US$479 (£234).
Despite the inclusion of new features, one expected improvement is yet to appear — WiMax connectivity. Nokia has already committed to launching WiMax-enabled products from next year and has previously hinted that the Linux tablet is in line for the connectivity upgrade.
In this short code snippet I will show you how to execute system commands like ping or nslookup or format c: ;-). The function we will use is rather intended to be used in textconsole based applications. But you could also use it in other programs.
That is our 'magic' function. You have to include stdlib.h to use it.
int system( constchar *command );
command is a string that holds the app's name with optional arguments. It is used like on the commandline. The good thing is that the text output that the application produces will be shown in your textconsole. You could now use it to program your own shell! Nice, isn't it? The return-value will be same as the the return-value of the system command only if there was an error, then it will be -1. Here's a little example:
#include .h> #include .h>
int main() { cout << "Executing ping..." << style="color: rgb(255, 0, 0);">"ping localhost"); cout << "Ping is done. I am done too. Let's shutdown and go for a drink." <<>
This simple code snippet outputs some text and then starts ping with argument localhost. The ouput of ping will be shown in your textconsole and it will be the same as if you run it on the shell.
2. In Java program (quoted from:http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=1) --------------------
As part of the Java language, the java.lang package is implicitly imported into every Java program. This package's pitfalls surface often, affecting most programmers. This month, I'll discuss the traps lurking in the Runtime.exec() method.
Pitfall 4: When Runtime.exec() won't
The class java.lang.Runtime features a static method called getRuntime(), which retrieves the current Java Runtime Environment. That is the only way to obtain a reference to the Runtime object. With that reference, you can run external programs by invoking the Runtime class's exec() method. Developers often call this method to launch a browser for displaying a help page in HTML.
There are four overloaded versions of the exec() command:
public Process exec(String command);
public Process exec(String [] cmdArray);
public Process exec(String command, String [] envp);
public Process exec(String [] cmdArray, String [] envp);
For each of these methods, a command -- and possibly a set of arguments -- is passed to an operating-system-specific function call. This subsequently creates an operating-system-specific process (a running program) with a reference to a Process class returned to the Java VM. The Process class is an abstract class, because a specific subclass of Process exists for each operating system.
You can pass three possible input parameters into these methods:
A single string that represents both the program to execute and any arguments to that program
An array of strings that separate the program from its arguments
An array of environment variables
Pass in the environment variables in the form name=value. If you use the version of exec() with a single string for both the program and its arguments, note that the string is parsed using white space as the delimiter via the StringTokenizer class.
Stumbling into an IllegalThreadStateException
The first pitfall relating to Runtime.exec() is the IllegalThreadStateException. The prevalent first test of an API is to code its most obvious methods. For example, to execute a process that is external to the Java VM, we use the exec() method. To see the value that the external process returns, we use the exitValue() method on the Process class. In our first example, we will attempt to execute the Java compiler (javac.exe):
Listing 4.1 BadExecJavac.java
import java.util.*; import java.io.*; public class BadExecJavac { public static void main(String args[]) { try { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("javac"); int exitVal = proc.exitValue(); System.out.println("Process exitValue: " + exitVal); } catch (Throwable t) { t.printStackTrace(); } } }
A run of BadExecJavac produces:
E:\classes\com\javaworld\jpitfalls\article2>java BadExecJavac java.lang.IllegalThreadStateException: process has not exited at java.lang.Win32Process.exitValue(Native Method) at BadExecJavac.main(BadExecJavac.java:13)
If an external process has not yet completed, the exitValue() method will throw an IllegalThreadStateException; that's why this program failed. While the documentation states this fact, why can't this method wait until it can give a valid answer?
A more thorough look at the methods available in the Process class reveals a waitFor() method that does precisely that. In fact, waitFor() also returns the exit value, which means that you would not use exitValue() and waitFor() in conjunction with each other, but rather would choose one or the other. The only possible time you would use exitValue() instead of waitFor() would be when you don't want your program to block waiting on an external process that may never complete. Instead of using the waitFor() method, I would prefer passing a boolean parameter called waitFor into the exitValue() method to determine whether or not the current thread should wait. A boolean would be more beneficial because exitValue() is a more appropriate name for this method, and it isn't necessary for two methods to perform the same function under different conditions. Such simple condition discrimination is the domain of an input parameter.
Therefore, to avoid this trap, either catch the IllegalThreadStateException or wait for the process to complete.
Now, let's fix the problem in Listing 4.1 and wait for the process to complete. In Listing 4.2, the program again attempts to execute javac.exe and then waits for the external process to complete:
Listing 4.2 BadExecJavac2.java
import java.util.*; import java.io.*; public class BadExecJavac2 { public static void main(String args[]) { try { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("javac"); int exitVal = proc.waitFor(); System.out.println("Process exitValue: " + exitVal); } catch (Throwable t) { t.printStackTrace(); } } }
Unfortunately, a run of BadExecJavac2 produces no output. The program hangs and never completes. Why does the javac process never complete?
Why Runtime.exec() hangs
The JDK's Javadoc documentation provides the answer to this question:
Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.
Is this just a case of programmers not reading the documentation, as implied in the oft-quoted advice: read the fine manual (RTFM)? The answer is partially yes. In this case, reading the Javadoc would get you halfway there; it explains that you need to handle the streams to your external process, but it does not tell you how.
Another variable is at play here, as is evident by the large number of programmer questions and misconceptions concerning this API in the newsgroups: though Runtime.exec() and the Process APIs seem extremely simple, that simplicity is deceiving because the simple, or obvious, use of the API is prone to error. The lesson here for the API designer is to reserve simple APIs for simple operations. Operations prone to complexities and platform-specific dependencies should reflect the domain accurately. It is possible for an abstraction to be carried too far. The JConfig library provides an example of a more complete API to handle file and process operations (see Resources below for more information).
Now, let's follow the JDK documentation and handle the output of the javac process. When you run javac without any arguments, it produces a set of usage statements that describe how to run the program and the meaning of all the available program options. Knowing that this is going to the stderr stream, you can easily write a program to exhaust that stream before waiting for the process to exit. Listing 4.3 completes that task. While this approach will work, it is not a good general solution. Thus, Listing 4.3's program is named MediocreExecJavac; it provides only a mediocre solution. A better solution would empty both the standard error stream and the standard output stream. And the best solution would empty these streams simultaneously (I'll demonstrate that later).
Listing 4.3 MediocreExecJavac.java
import java.util.*; import java.io.*; public class MediocreExecJavac { public static void main(String args[]) { try { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("javac"); InputStream stderr = proc.getErrorStream(); InputStreamReader isr = new InputStreamReader(stderr); BufferedReader br = new BufferedReader(isr); String line = null; System.out.println(""); while ( (line = br.readLine()) != null) System.out.println(line); System.out.println(""); int exitVal = proc.waitFor(); System.out.println("Process exitValue: " + exitVal); } catch (Throwable t) { t.printStackTrace(); } } }
A run of MediocreExecJavac generates:
E:\classes\com\javaworld\jpitfalls\article2>java MediocreExecJavac Usage: javac where includes: -g Generate all debugging info -g:none Generate no debugging info -g:{lines,vars,source} Generate only some debugging info -O Optimize; may hinder debugging or enlarge class files -nowarn Generate no warnings -verbose Output messages about what the compiler is doing -deprecation Output source locations where deprecated APIs are used -classpath Specify where to find user class files -sourcepath Specify where to find input source files -bootclasspath Override location of bootstrap class files -extdirs Override location of installed extensions -d Specify where to place generated class files -encoding Specify character encoding used by source files -target Generate class files for specific VM version
Process exitValue: 2
So, MediocreExecJavac works and produces an exit value of 2. Normally, an exit value of 0 indicates success; any nonzero value indicates an error. The meaning of these exit values depends on the particular operating system. A Win32 error with a value of 2 is a "file not found" error. That makes sense, since javac expects us to follow the program with the source code file to compile.
Thus, to circumvent the second pitfall -- hanging forever in Runtime.exec() -- if the program you launch produces output or expects input, ensure that you process the input and output streams.
Assuming a command is an executable program
Under the Windows operating system, many new programmers stumble upon Runtime.exec() when trying to use it for nonexecutable commands like dir and copy. Subsequently, they run into Runtime.exec()'s third pitfall. Listing 4.4 demonstrates exactly that:
Listing 4.4 BadExecWinDir.java
import java.util.*; import java.io.*; public class BadExecWinDir { public static void main(String args[]) { try { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("dir"); InputStream stdin = proc.getInputStream(); InputStreamReader isr = new InputStreamReader(stdin); BufferedReader br = new BufferedReader(isr); String line = null; System.out.println(""); int exitVal = proc.waitFor(); System.out.println("Process exitValue: " + exitVal); } catch (Throwable t) { t.printStackTrace(); } } }
A run of BadExecWinDir produces:
E:\classes\com\javaworld\jpitfalls\article2>java BadExecWinDir java.io.IOException: CreateProcess: dir error=2 at java.lang.Win32Process.create(Native Method) at java.lang.Win32Process.(Unknown Source) at java.lang.Runtime.execInternal(Native Method) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at BadExecWinDir.main(BadExecWinDir.java:12)
As stated earlier, the error value of 2 means "file not found," which, in this case, means that the executable named dir.exe could not be found. That's because the directory command is part of the Windows command interpreter and not a separate executable. To run the Windows command interpreter, execute either command.com or cmd.exe, depending on the Windows operating system you use. Listing 4.5 runs a copy of the Windows command interpreter and then executes the user-supplied command (e.g., dir).
// any output? StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT");
// kick them off errorGobbler.start(); outputGobbler.start();
// any error??? int exitVal = proc.waitFor(); System.out.println("ExitValue: " + exitVal); } catch (Throwable t) { t.printStackTrace(); } } }
Running GoodWindowsExec with the dir command generates:
E:\classes\com\javaworld\jpitfalls\article2>java GoodWindowsExec "dir *.java" Execing cmd.exe /C dir *.java OUTPUT> Volume in drive E has no label. OUTPUT> Volume Serial Number is 5C5F-0CC9 OUTPUT> OUTPUT> Directory of E:\classes\com\javaworld\jpitfalls\article2 OUTPUT> OUTPUT>10/23/00 09:01p 805 BadExecBrowser.java OUTPUT>10/22/00 09:35a 770 BadExecBrowser1.java OUTPUT>10/24/00 08:45p 488 BadExecJavac.java OUTPUT>10/24/00 08:46p 519 BadExecJavac2.java OUTPUT>10/24/00 09:13p 930 BadExecWinDir.java OUTPUT>10/22/00 09:21a 2,282 BadURLPost.java OUTPUT>10/22/00 09:20a 2,273 BadURLPost1.java ... (some output omitted for brevity) OUTPUT>10/12/00 09:29p 151 SuperFrame.java OUTPUT>10/24/00 09:23p 1,814 TestExec.java OUTPUT>10/09/00 05:47p 23,543 TestStringReplace.java OUTPUT>10/12/00 08:55p 228 TopLevel.java OUTPUT> 22 File(s) 46,661 bytes OUTPUT> 19,678,420,992 bytes free ExitValue: 0
Running GoodWindowsExec with any associated document type will launch the application associated with that document type. For example, to launch Microsoft Word to display a Word document (i.e., one with a .doc extension), type:
>java GoodWindowsExec "yourdoc.doc"
Notice that GoodWindowsExec uses the os.name system property to determine which Windows operating system you are running -- and thus determine the appropriate command interpreter. After executing the command interpreter, handle the standard error and standard input streams with the StreamGobbler class. StreamGobbler empties any stream passed into it in a separate thread. The class uses a simple String type to denote the stream it empties when it prints the line just read to the console.
Thus, to avoid the third pitfall related to Runtime.exec(), do not assume that a command is an executable program; know whether you are executing a standalone executable or an interpreted command. At the end of this section, I will demonstrate a simple command-line tool that will help you with that analysis.
It is important to note that the method used to obtain a process's output stream is called getInputStream(). The thing to remember is that the API sees things from the perspective of the Java program and not the external process. Therefore, the external program's output is the Java program's input. And that logic carries over to the external program's input stream, which is an output stream to the Java program.
Runtime.exec() is not a command line
One final pitfall to cover with Runtime.exec() is mistakenly assuming that exec() accepts any String that your command line (or shell) accepts. Runtime.exec() is much more limited and not cross-platform. This pitfall is caused by users attempting to use the exec() method to accept a single String as a command line would. The confusion may be due to the fact that command is the parameter name for the exec() method. Thus, the programmer incorrectly associates the parameter command with anything that he or she can type on a command line, instead of associating it with a single program and its arguments. In listing 4.6 below, a user tries to execute a command and redirect its output in one call to exec():
Listing 4.6 BadWinRedirect.java
import java.util.*; import java.io.*; // StreamGobbler omitted for brevity public class BadWinRedirect { public static void main(String args[]) { try { Runtime rt = Runtime.getRuntime(); Process proc = rt.exec("java jecho 'Hello World' > test.txt"); // any error message? StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR");
// any output? StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT");
// kick them off errorGobbler.start(); outputGobbler.start();
// any error??? int exitVal = proc.waitFor(); System.out.println("ExitValue: " + exitVal); } catch (Throwable t) { t.printStackTrace(); } } }
The program BadWinRedirect attempted to redirect the output of an echo program's simple Java version into the file test.txt. However, we find that the file test.txt does not exist. The jecho program simply takes its command-line arguments and writes them to the standard output stream. (You will find the source for jecho in the source code available for download in Resources.) In Listing 4.6, the user assumed that you could redirect standard output into a file just as you could on a DOS command line. Nevertheless, you do not redirect the output through this approach. The incorrect assumption here is that the exec() method acts like a shell interpreter; it does not. Instead, exec() executes a single executable (a program or script). If you want to process the stream to either redirect it or pipe it into another program, you must do so programmatically, using the java.io package. Listing 4.7 properly redirects the standard output stream of the jecho process into a file.
After running GoodWinRedirect, test.txt does exist. The solution to the pitfall was to simply control the redirection by handling the external process's standard output stream separately from the Runtime.exec() method. We create a separate OutputStream, read in the filename to which we redirect the output, open the file, and write the output that we receive from the spawned process's standard output to the file. Listing 4.7 completes that task by adding a new constructor to our StreamGobbler class. The new constructor takes three arguments: the input stream to gobble, the type String that labels the stream we are gobbling, and the output stream to which we redirect the input. This new version of StreamGobbler does not break any of the code in which it was previously used, as we have not changed the existing public API -- we only extended it.
Since the argument to Runtime.exec() is dependent on the operating system, the proper commands to use will vary from one OS to another. So, before finalizing arguments to Runtime.exec() and writing the code, quickly test the arguments. Listing 4.8 is a simple command-line utility that allows you to do just that.
Here's a useful exercise: try to modify TestExec to redirect the standard input or standard output to a file. When executing the javac compiler on Windows 95 or Windows 98, that would solve the problem of error messages scrolling off the top of the limited command-line buffer.
Listing 4.8 TestExec.java
import java.util.*; import java.io.*; // class StreamGobbler omitted for brevity public class TestExec { public static void main(String args[]) { if (args.length < cmd =" args[0];" rt =" Runtime.getRuntime();" proc =" rt.exec(cmd);" errorgobbler =" new" outputgobbler =" new" exitval =" proc.waitFor();">
Running TestExec to launch the Netscape browser and load the Java help documentation produces:
E:\classes\com\javaworld\jpitfalls\article2>java TestExec "e:\java\docs\index.html" java.io.IOException: CreateProcess: e:\java\docs\index.html error=193 at java.lang.Win32Process.create(Native Method) at java.lang.Win32Process.(Unknown Source) at java.lang.Runtime.execInternal(Native Method) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at TestExec.main(TestExec.java:45)
Our first test failed with an error of 193. The Win32 error for value 193 is "not a valid Win32 application." This error tells us that no path to an associated application (e.g., Netscape) exists, and that the process cannot run an HTML file without an associated application.
Therefore, we try the test again, this time giving it a full path to Netscape. (Alternately, we could add Netscape to our PATH environment variable.) A second run of TestExec produces:
This worked! The Netscape browser launches, and it then loads the Java help documentation.
One additional improvement to TestExec would include a command-line switch to accept input from standard input. You would then use the Process.getOutputStream() method to pass the input to the spawned external program.
To sum up, follow these rules of thumb to avoid the pitfalls in Runtime.exec():
You cannot obtain an exit status from an external process until it has exited
You must immediately handle the input, output, and error streams from your spawned external process
There are also files that are created by LaTeX2e, the .aux file, the .toc file and the .bib file. The .aux (auxiliary) file is where LaTeX stores all the information about the counters (like section numbers), footnotes, bibliography entries, reference marks, and anything else that LaTeX may need to keep track of. This file is written over whenever a file is typeset by LaTeX. Whenever a document is typeset LaTeX reads this file to get the information it need, and writes to it after typesetting is completed. This is why changes in the counters will not take effect until LaTeX is run twice, because the .aux file is not up to date the first time. The .bib file is where all the bibliography information is kept. You can either make this file yourself, or you can use BibTeX to create the file. The .toc file contains all the information needed to create the Table of Contents. This file is created when LaTeX sees the command \tableofcontents, and the section names, numbers and page numbers are all read from the .aux file.