Writing to File Example
We will be continuing what we started in the previous article. In this example, we are going to write a script that repeatedly accepts lines of input from the user, and writes them one after another to a file.
open (FILEOUT, '>', "/tmp/userinput.txt");
while(($input = <stdin>) != "\n")
print FILEOUT ($input);
When executed, the script should behave as follows:
- The open function opens the file handle FILEOUT for output to the file /tmp/userinput.txt.
- The while loop will continue to accept lines of input from the standard input as long as the user enters non-empty lines (the empty line will consist only of a newline character).
- The print function writes the variable $input to the file via the FILEOUT file handle.
Appending To File Example
In this example, we are going to open the /etc/hosts file, and append a line to it.
First, let’s display the current contents of the file.
Then, consider the following script:
open (APPENDFILE, '>>', "/etc/hosts");
print APPENDFILE ("192.168.1.150 fedora20_srv\n");
When executed, the script will not display any output. To verify it worked as desired, display the contents of /etc/hosts file again:
Input from Multiple, Dynamically Specified Files
So far, we have learned two methods for input:
- Reading from the standard input using the <stdin> operator.
- Using the open function to open a file handle (say for example FILEREAD) for reading from a specific file, then using the <FILEREAD> operator to read line by line.
Both methods have something common; the <> operator. Actually, they are not two methods; it is only one, with only the file handle (inside the <> operator) changed. When reading a line from the standard input, the special file handle stdin is used.
On the other hand, when reading from a file, we define a file handle of our choice, and then use it inside the <> operator. Also, to read from a file, we need to know the file name (and of course its path) in advance. Otherwise, Perl will complain.
This is only for reading from one file. What if we need to read from multiple files?! A separate open statement will be needed for each file, along with a separate file handle, and of course a separate < >.
Moreover, this is a static way. Filenames are needed when the open function gets called; therefore, they must be known in advance. What if we need to specify filenames dynamically at run time?
Fortunately, Perl and its <> operator were nice enough to provide us with a way to specify the input file(s) at runtime. In this way, the user can provide names for one or more files at runtime as command-line arguments. The diamond operator <> then starts reading the files one by one. It reads the first file, line by line, until the end of file is reached, then it starts reading the second file, and so on.
Let’s see how to do this using an example.
File Concatenation Example
In this example, we are going to write a script that performs the functionality of the cat command. If you have some knowledge of UNIX or Linux, you would know that cat concatenates files and prints them on the standard output. Okay, let’s develop.
You may be wondering now: would that five-lines short script concatenate multiple files, and write the output to the screen? My answer is: Yes! One day I will show you how to do the same functionality using only one line of code.
Okay, let the script talk about itself:
Before executing the script, let’s first create some files (that we will concatenate later).
Now, execute the script. For displaying contents of one file:
Concatenating and printing two files:
For three files:
To concatenate all files in the current directory (including the script itself):
Handling File Operations Errors
As a developer, you should be prepared for situations wherein file I/O errors are encountered. Consider trying to open for reading a file that doesn’t exist, or trying to open a file for writing while you have no write permission on it. For example, the following open statement will not be executed successfully:
open (PASSWDFILE, '<', "/etc/passwd_11");
Unfortunately, the script will not generate any errors, and the exit status of the script will be 0 (successful execution). This is although the script hasn’t printed anything!!
For such situations, Perl has a useful function die() that could print a custom error message to the standard error, and at the same time, returns a non-zero exit status.
open (PASSWDFILE, '<', "/etc/passwd_11") or die("The specified file doesn't exist!!!");
In this article, we have continued what we started in the previous one. We have learned how to write and append to a file.
The diamond operator <> can be used to read lines from multiple files in sequence. The filenames are provided at runtime as command-line arguments.
Finally, we have seen that errors can be handled using the die() function. This function prints a message to the standard error, and returns a non-zero exit status.
That is it for I/O. In the next article, we will switch back to variables, and talk about the third type of variables: Hashes. See you.