This Java project provides a cross-platform CLI tool for managing processes, simplifying a task that would otherwise require using different, complex commands on various operating systems. It offers a single, intuitive interface for actions like finding a process by its port or killing a process by its PID, abstracting away the underlying OS commands.
Project Tutorial: Process Killer CLI Tool
Setting Up the Project
- Project Structure: Create a new Java project with a single class
App.java
inside a package namedcom.process_killer
. You can use any IDE like IntelliJ IDEA or VS Code. - Dependencies: This project uses only the Java Standard Library, so no external dependencies are needed.
The Code Explained
The App.java
class contains several methods, each responsible for a specific part of the application's functionality.
main(String[] args)
This is the main entry point of the application. It initializes a Scanner
for user input and a String
variable to store the OS name. It then enters an infinite loop, constantly prompting the user for a command. The loop breaks only when the user types "q". Inside the loop, it validates the command and dispatches it to the appropriate method (kill
, find
, or refresh
).
printProcess()
This method is responsible for listing all active processes with their associated ports. It checks the operating system (SYSTEM
) to determine the correct command to execute:
-
Windows: It uses
netstat -ano
. -
Linux/macOS: It uses
lsof -i -P -n
. It then executes this command using aProcessBuilder
, reads the output line by line, and prints it to the console.
processFindCommand(String[] arr)
This method handles the "find" command.
- Validation: It first validates the command's format and the port number using the
validate
method. - Command Execution: Similar to
printProcess()
, it selects the appropriate command based on the OS.-
Windows:
netstat -ano | findstr :<port>
-
Linux/macOS:
lsof -t -i :<port>
-
Windows:
- Output Parsing: It executes the command and reads the output to find the PID. The code then parses the output to extract the PID and prints it.
processKillCommand(String[] arr)
This method handles the "kill" command. It validates that the user-provided PID is a valid number. If it is, it calls the killProcess
method to perform the actual killing.
killProcess(String pid)
This method terminates a process given its PID.
- Command Selection: It determines the correct command to kill a process based on the OS.
-
Windows:
taskkill /PID <pid> /F
(the/F
flag forces termination). -
Linux/macOS:
kill -9 <pid>
(the-9
signal ensures immediate termination).
-
Windows:
- Execution: It executes the command, waits for it to complete, and then prints a confirmation message. After killing the process, it calls
printProcess()
to refresh and display the updated process list.
validate(String pid)
This helper method checks if a given string is a valid integer. It uses a try-catch
block with Integer.parseInt()
. If the parsing is successful, it returns true
; otherwise, it returns false
, preventing the program from crashing on invalid input.
Improved Code
The original code is functional, but it can be improved with better structure and modularity. A ProcessManager
class can abstract the OS-specific commands, making the App
class cleaner and easier to read.
package com.process_killer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* A simple cross-platform command-line utility for managing processes by PID or Port.
*/
public class App {
private static final Scanner INPUT = new Scanner(System.in);
private static final ProcessManager PROCESS_MANAGER = new ProcessManager();
public static void main(String[] args) {
PROCESS_MANAGER.printProcess();
while (true) {
System.out.print(": ");
var input = INPUT.nextLine();
if (input.equalsIgnoreCase("q")) {
break;
}
var arr = input.split(" ");
var command = arr[0];
switch (command) {
case "kill":
PROCESS_MANAGER.killProcess(arr);
break;
case "find":
PROCESS_MANAGER.findProcess(arr);
break;
case "refresh":
PROCESS_MANAGER.printProcess();
break;
default:
System.out.println("Invalid Command!");
}
}
}
}
class ProcessManager {
/** Current operating system name (lowercase). */
private static final String SYSTEM = System.getProperty("os.name").toLowerCase();
/**
* Executes a command and returns the output as a list of strings.
* @param command The command to execute.
* @return A list of strings representing the command's output.
*/
private List<String> executeCommand(List<String> command) throws IOException {
List<String> output = new ArrayList<>();
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true); // Combine standard and error streams
Process process = processBuilder.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
output.add(line);
}
}
return output;
}
/**
* Prints currently running processes and their associated ports.
*/
public void printProcess() {
List<String> command = new ArrayList<>();
if (SYSTEM.contains("win")) {
command.add("cmd.exe");
command.add("/c");
command.add("netstat -ano");
} else {
command.add("bash");
command.add("-c");
command.add("lsof -i -P -n");
}
try {
List<String> output = executeCommand(command);
output.forEach(System.out::println);
} catch (IOException e) {
System.out.printf("Sorry, an internal error occurred: %s%n", e.getMessage());
}
}
/**
* Finds the PID of the process using a specific port.
* @param arr command arguments ("find by <port>")
*/
public void findProcess(String[] arr) {
if (arr.length != 3) {
System.out.println("Invalid Command! Usage: find by <port>");
return;
}
if (!validate(arr[2])) {
System.out.println("Invalid Port! Port must be a number.");
return;
}
List<String> findCommand = new ArrayList<>();
if (SYSTEM.contains("win")) {
findCommand.add("cmd.exe");
findCommand.add("/c");
findCommand.add("netstat -ano | findstr :" + arr[2]);
} else {
findCommand.add("bash");
findCommand.add("-c");
findCommand.add("lsof -t -i :" + arr[2]);
}
try {
List<String> output = executeCommand(findCommand);
if (output.isEmpty()) {
System.out.println("No process found on port " + arr[2]);
} else {
// Simplified output processing (might need more robust parsing)
String result = output.get(output.size() - 1);
var resArr = result.trim().split(" ");
System.out.println("Found process on port " + arr[2] + " with PID: " + resArr[resArr.length - 1].trim());
}
} catch (IOException ex) {
System.out.printf("Failed to find Process running on port %s: %s%n", arr[2], ex.getMessage());
}
}
/**
* Kills a process by PID.
* @param arr command arguments ("kill <pid>")
*/
public void killProcess(String[] arr) {
if (arr.length != 2) {
System.out.println("Invalid Command! Usage: kill <pid>");
return;
}
String pid = arr[1];
if (!validate(pid)) {
System.out.println("Invalid PID! PID must be a number.");
return;
}
List<String> killCommand = new ArrayList<>();
if (SYSTEM.contains("win")) {
killCommand.add("cmd.exe");
killCommand.add("/c");
killCommand.add("taskkill /PID " + pid + " /F");
} else {
killCommand.add("bash");
killCommand.add("-c");
killCommand.add("kill -9 " + pid);
}
try {
executeCommand(killCommand);
System.out.println("Killed process " + pid);
printProcess(); // Refresh the list
} catch (IOException e) {
System.out.printf("Failed to kill process %s: %s%n", pid, e.getMessage());
}
}
/**
* Validates whether a given string is a number.
* @param input string representing a number
* @return true if valid integer, false otherwise
*/
private boolean validate(String input) {
try {
Integer.parseInt(input);
return true;
} catch (NumberFormatException ex) {
return false;
}
}
}
How to Use the Tool
To use the tool, you'll first need to compile and run the Java code. Once it's running, a prompt >
will appear, indicating that the tool is ready to accept commands.
1. Listing All Processes
When you start the application, it automatically lists all currently running processes and their associated ports. This is a great starting point to see what's active on your system. You can also manually refresh the list at any time.
-
Command:
refresh
- What it does: Reruns the process listing command to show the most up-to-date processes.
2. Finding a Process by Port
If you need to find a process that is using a specific port, this command will quickly return its Process ID (PID). This is particularly useful for stopping services that are causing port conflicts.
-
Command:
find by <port>
-
Example:
find by 8080
-
What it does: Searches for any process listening on port
8080
and displays its PID.
3. Killing a Process
Once you have the PID of a process you want to terminate, you can use the kill
command. The tool will then attempt to forcefully stop the process.
-
Command:
kill <pid>
-
Example:
kill 12345
-
What it does: Terminates the process with the PID
12345
. After a successful kill, it automatically refreshes the process list so you can confirm the process is gone.
4. Quitting the Tool
To exit the application, simply type q
and press Enter.
-
Command:
q
- What it does: Closes the application and returns you to your operating system's command prompt.
Key Commands at a Glance
Command | Usage | Description |
---|---|---|
refresh |
refresh |
Lists all running processes and their ports. |
find |
find by <port> |
Finds the PID of the process using a specific port. |
kill |
kill <pid> |
Kills the process with the specified PID. |
q |
q |
Quits the application. |
Why Build This Project?
Even though you can use command-line tools directly, a dedicated Java application offers several key advantages:
- Platform Independence: The biggest benefit is not having to remember different commands for different operating systems.
netstat
,lsof
,taskkill
, andkill
are all handled internally. The user only needs to remember one set of commands. - User-Friendly Interface: The application provides clear, simple commands like
kill <pid>
andfind by <port>
, making it easier to use for those unfamiliar with command-line syntax. - Step-by-Step Guidance: The interactive nature and output provide a clear, step-by-step process. You can list processes, find the one you need, and then kill it, all within the same tool.
Top comments (0)