UNIX PROGRAMMING
Lab Manual
BCA 5th SEM
I. SHELL commands in UNIX
File and Directory Management Commands
1. List Files and Directories
sh
ls # Basic list of files in the current directory
ls -l # Detailed list, including permissions, size, and modification time
ls -a # Show hidden files (files starting with .)
Output
2. Change Directory
sh
cd Documents # Change to the "Documents" directory
cd .. # Go up one directory level
cd ~ # Go to the user's home directory
Output
3. Print Working Directory
sh
pwd # Shows the full path of the current directory
Output
4. Make a New Directory
sh
mkdir new_folder # Create a directory named "new_folder" in the current directory
Output
5. Remove an Empty Directory
sh
rmdir old_folder # Remove an empty directory named "old_folder"
Output
6. Create a New File or Update Timestamp
sh
touch example.txt # Creates an empty file named "example.txt" or updates the timestamp if it exists
Output
7. Copy Files and Directories
sh
cp file1.txt file2.txt # Copy "file1.txt" to a new file named "file2.txt"
cp -r folder1 folder2 # Copy "folder1" and its contents to "folder2"
Output
8. Move or Rename Files and Directories
sh
mv file1.txt newfile.txt # Rename "file1.txt" to "newfile.txt"
mv old_folder new_folder # Rename "old_folder" to "new_folder"
Output
9. Delete a File or Directory
sh
rm unwanted_file.txt # Delete "unwanted_file.txt"
rm -r unwanted_folder # Delete "unwanted_folder" and all its contents recursively
Output
Viewing File Contents
1. Display File Contents
sh
cat file.txt # Show the contents of "file.txt"
Output
2. View File One Screen at a Time
sh
more file.txt # View "file.txt" one screen at a time
less file.txt # View "file.txt" with navigation options
Output
3. Show Beginning and End of File
sh
head file.txt # Display the first 10 lines of "file.txt"
head -n 5 file.txt # Show the first 5 lines of "file.txt"
tail file.txt # Display the last 10 lines of "file.txt"
tail -n 5 file.txt # Show the last 5 lines of "file.txt"
Output
System Information
1. Show Current User
sh
whoami # Display the current user's name
Output
2. System Information
sh
uname -a # Detailed information about the system
Output
3. Disk Space
sh
df # Show available disk space on file systems
df -h # Disk space in human-readable format (KB, MB, etc.)
Output
4. Running Processes and System Usage
sh
top # Display running processes and system usage in real-time
Output
5. List Processes
sh
ps # List processes running in the current shell
ps aux # Show all running processes with details
Output
Permissions and Ownership
1. Change File Permissions
sh
chmod 755 script.sh # Set permissions to read/write/execute for the owner, read/execute for others
Output
2. Change File Owner and Group
sh
chown user:group file.txt # Change owner and group of "file.txt" to "user" and "group"
Output
Text Print and Manipulation Commands
1. echo – Print simple text or variables to the terminal.
sh
echo "Hello, Unix!" # Print "Hello, Unix!" to the terminal
echo "User: $USER" # Print the value of the environment variable $USER
Output
2. printf – Similar to echo, but allows formatted text (like C’s printf).
sh
printf "Name: %s, Age: %d\n" John 25 # Print formatted output: "Name: John, Age: 25"
Output
3. cat – Concatenate and display files or standard input.
sh
cat file.txt # Print the contents of "file.txt"
cat file1.txt file2.txt # Concatenate and display contents of both files
Output
4. tac – Print file contents in reverse order (last line first).
sh
tac file.txt # Display "file.txt" contents in reverse order
Output
5. nl – Print a file with line numbers.
sh
nl file.txt # Display "file.txt" with line numbers
Output
6. head – Display the first few lines of a file.
sh
head -n 5 file.txt # Print the first 5 lines of "file.txt"
Output
7. tail – Display the last few lines of a file.
sh
tail -n 5 file.txt # Print the last 5 lines of "file.txt"
Output
8. more – View file contents one screen at a time.
sh
more file.txt # Display "file.txt" with pagination
Output
9. less – Similar to more but allows backward navigation.
sh
less file.txt # View "file.txt" with more navigation options
Output
10. awk – A powerful text processing command, often used for parsing and printing specific parts of a file.
sh
awk '{print $1}' file.txt # Print the first field of each line in "file.txt"
Output
11. sed – Stream editor for filtering and transforming text.
sh
sed 's/old/new/g' file.txt # Replace "old" with "new" in "file.txt"
Output
12. grep – Search for patterns in text and print matching lines.
sh
grep "pattern" file.txt # Print lines in "file.txt" that match "pattern"
Output
13. echo -e – Allows escape sequences for formatted text.
sh
echo -e "Line1\nLine2\nLine3" # Print multiple lines
Output
14. Combine commands to create complex output:
sh
echo "Today is $(date)" # Use command substitution to include date output
Output
15. Use pipes (|) to combine commands:
sh
cat file.txt | grep "error" # Display lines with "error" from "file.txt"
Output
16. Print Text to Terminal
sh
echo "Hello, World!" # Print "Hello, World!" to the terminal
Output
II. Programs using Inter Process Communication (IPC)
To execute C programs that use IPC mechanisms in UNIX, you need to follow these steps:
1. Write the Code in a File: Save each program in a separate .c file, e.g., pipe_example.c,
message_queue_example.c, etc.
2. Compile the Program Using GCC: Use the GNU Compiler Collection (gcc) to compile the C
programs. You can run each program using the following command in your terminal:
bash
gcc -o program_name file_name.c
-o program_name specifies the output executable file name.
file_name.c is the name of your C source file.
3. Run the Executable: After successful compilation, run the program by typing:
bash
./program_name
1. Pipes
Pipes provide a one-way communication channel between processes.
Anonymous Pipes are commonly used for parent-child process communication.
Named Pipes (FIFO) can be used between unrelated processes.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
int main() {
int pipefds[2];
char buffer[5];
pipe(pipefds); // create pipe
if (fork() == 0) {
close(pipefds[0]); // close reading end
write(pipefds[1], "Hello", 5);
close(pipefds[1]); // close writing end
} else {
close(pipefds[1]); // close writing end
read(pipefds[0], buffer, 5);
printf("Received: %s\n", buffer);
close(pipefds[0]); // close reading end
}
return 0;
}
Compile the Program
Command to compile pipe_example.c: gcc -o pipe_example pipe_example.c
Run the Program
Execute the compiled program: ./pipe_example
2. Message Queues
Message queues allow processes to exchange messages in a structured way.
Each message has a type and content, allowing selective retrieval of messages.
Operations are based on the msgget, msgsnd, and msgrcv system calls.
Create the Sender Program – Save the file as msg_sender.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
struct msgbuf
{
long mtype;
char mtext[100];
};
int main()
{
int msgid;
struct msgbuf message;
// create a message queue
msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
if (msgid < 0)
{
perror("msgget");
exit(1);
// prepare message
message.mtype = 1;
// Message type
strcpy(message.mtext, "Hello from sender!");
// Send the message
if (msgsnd(msgid, &message, sizeof(message.mtext), 0) < 0)
{
perror("msgsnd");
exit(1);
}
printf("Message sent: %s\n", message.mtext);
// Clean up
msgctl(msgid, IPC_RMID, NULL); // Remove the message queue
return 0;
}
Create Receiver Program - Save the file as msg_receiver.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
struct msgbuf
{
long mtype;
char mtext[100];
};
int main()
{
int msgid;
struct msgbuf message;
// Create or connect to the message queue (you can use the same key as in sender)
msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
if (msgid < 0)
{
perror("msgget");
exit(1);
}
// Receive the message
if (msgrcv(msgid, &message, sizeof(message.mtext), 1, 0) < 0)
{
perror("msgrcv");
exit(1);
}
printf("Received message: %s\n", message.mtext);
// Clean up
msgctl(msgid, IPC_RMID, NULL); // Remove the message queue
return 0;
}
Compile the Programs
gcc -o msg_sender msg_sender.c
gcc -o msg_receiver msg_receiver.c
Execute the Programs
1. First, run the receiver in one terminal window: ./msg_receiver
2. In another terminal window, run the sender: ./msg_sender
3. Shared Memory
Shared memory provides a region of memory accessible by multiple processes.
It's the fastest IPC method as it allows direct memory access.
Operations are based on shmget, shmat, shmdt, and shmctl.
Create the Writer Program Save the file as shm_writer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#define SHM_SIZE 1024 // Define the size of the shared memory
int main()
{
int shmid;
char *data;
// Create shared memory segment
shmid = shmget(IPC_PRIVATE, SHM_SIZE, 0666 | IPC_CREAT);
if (shmid < 0)
{
perror("shmget");
exit(1);
}
// Attach the shared memory segment
data = (char *)shmat(shmid, NULL, 0);
if (data == (char *)(-1)) {
perror("shmat");
exit(1);
}
// Write to the shared memory
strcpy(data, "Hello from writer!");
printf("Writer: Data written to shared memory: %s\n", data);
// Detach from shared memory
shmdt(data);
return 0;
}
Create the Reader Program - Save the file as shm_reader.c.
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#define SHM_SIZE 1024 // Same size as the writer
int main()
{
int shmid;
char *data;
// Create or connect to the shared memory segment (use the same key as in writer)
shmid = shmget(IPC_PRIVATE, SHM_SIZE, 0666 | IPC_CREAT);
if (shmid < 0) {
perror("shmget");
exit(1);
}
// Attach the shared memory segment
data = (char *)shmat(shmid, NULL, 0);
if (data == (char *)(-1))
{
perror("shmat");
exit(1);
}
// Read from the shared memory
printf("Reader: Data read from shared memory: %s\n", data);
// Detach from shared memory
shmdt(data);
// Remove the shared memory segment
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
Compile the Programs: compile both programs: gcc -o shm_writer shm_writer.c
gcc -o shm_reader shm_reader.c
Execute the Programs
1. First, run the writer in one terminal window: ./shm_writer
2. In another terminal window, run the reader: ./shm_reader
4. Semaphores
Semaphores are used for controlling access to shared resources.
They help synchronize processes by preventing race conditions.
Operations use semget, semop, and semctl
Create the Producer Program - Save the file as producer.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 1024 // Size of the shared memory
#define SEM_KEY 1234 // Semaphore key
void P(int semid)
{ // Wait (decrement)
struct sembuf sb = {0, -1, 0};
semop(semid, &sb, 1);
}
void V(int semid)
{
// Signal (increment)
struct sembuf sb = {0, 1, 0};
semop(semid, &sb, 1);
}
int main()
{
int shmid, semid;
char *data;
// create shared memory
shmid = shmget(IPC_PRIVATE, SHM_SIZE, 0666 | IPC_CREAT);
if (shmid < 0) {
perror("shmget");
exit(1);
}
// Create semaphore
semid = semget(SEM_KEY, 1, 0666 | IPC_CREAT);
if (semid < 0) {
perror("semget");
exit(1);
}
// Initialize semaphore to 1 (binary semaphore)
semctl(semid, 0, SETVAL, 1);
// Attach the shared memory
data = (char *)shmat(shmid, NULL, 0);
if (data == (char *)(-1)) {
perror("shmat");
exit(1);
}
// Produce data
P(semid); // Wait
strcpy(data, "Produced Data");
printf("Producer: %s\n", data);
V(semid); // Signal
// Detach and clean up
shmdt(data);
shmctl(shmid, IPC_RMID, NULL);
semctl(semid, 0, IPC_RMID);
return 0;
}
Create the Consumer Program - Save the file as consumer.c.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 1024 // Size of the shared memory
#define SEM_KEY 1234 // Semaphore key
void P(int semid)
{
// Wait (decrement)
struct sembuf sb = {0, -1, 0};
semop(semid, &sb, 1);
}
void V(int semid)
{
// Signal (increment)
struct sembuf sb = {0, 1, 0};
semop(semid, &sb, 1);
}
int main()
{
int shmid, semid;
char *data;
// Create shared memory
shmid = shmget(IPC_PRIVATE, SHM_SIZE, 0666 | IPC_CREAT);
if (shmid < 0) {
perror("shmget");
exit(1);
}
// Get semaphore
semid = semget(SEM_KEY, 1, 0666);
if (semid < 0) {
perror("semget");
exit(1);
}
// Attach the shared memory
data = (char *)shmat(shmid, NULL, 0);
if (data == (char *)(-1)) {
perror("shmat");
exit(1);
}
// Consume data
P(semid); // Wait
printf("Consumer: %s\n", data);
V(semid); // Signal
// Detach and clean up
shmdt(data);
shmctl(shmid, IPC_RMID, NULL);
semctl(semid, 0, IPC_RMID);
return 0;
}
Compile the Programs
gcc -o producer producer.c
gcc -o consumer consumer.c
Execute the Programs
1. First, run the producer in one terminal window: ./producer
2. In another terminal window, run the consumer: ./consumer
III. Socket programming is a way to enable communication between processes over a network. It allows for
the development of client-server applications where one process (the server) listens for incoming requests
and the other (the client) initiates the communication.
TCP Socket Programming in C - A server program and a client program.
Create the Server Program - Save the file as tcp_server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
int main()
{
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
// Create socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
// Define the address
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// Bind the socket
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
// Start listening for connections
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server is listening on port %d\n", PORT);
// Accept a connection
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
// Read data from the client
read(new_socket, buffer, 1024);
printf("Received: %s\n", buffer);
// Send a response to the client
char *response = "Hello from server";
send(new_socket, response, strlen(response), 0);
printf("Response sent to client\n");
// Close the sockets
close(new_socket);
close(server_fd);
return 0;
}
Create the Client Program - Save the file as tcp_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 8080
int main()
{
int sock = 0;
struct sockaddr_in serv_addr;
char *message = "Hello from client";
char buffer[1024] = {0};
// Create socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
// Connect to the server
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
}
// Send message to the server
send(sock, message, strlen(message), 0);
printf("Message sent to server\n");
// Read response from the server
read(sock, buffer, 1024);
printf("Server response: %s\n", buffer);
/ Close the socket
close(sock);
return 0;
}
Compile the Programs: gcc -o tcp_server tcp_server.c gcc -o tcp_client tcp_client.c
Execute the Programs
1. First, run the server in one terminal window: ./tcp_server
2. In another terminal window, run the client: ./tcp_client