diff --git a/cbutil/cpu_frequency.py b/cbutil/cpu_frequency.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a628c079c21fa30b5bf4a43a7f71a0ab1c9d775
--- /dev/null
+++ b/cbutil/cpu_frequency.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+
+import subprocess
+import re
+import logging
+import argparse
+
+logger = logging.getLogger(__file__)
+
+# tuples with filepath and conversion_factor to Hz
+FREQUENCY_FILES = [
+    ("/sys/devices/system/cpu/cpu0/cpufreq/bios_limit", 1e3),  # KHZ
+    ("/sys/devices/system/cpu/cpu0/cpufreq/base_frequency", 1e3)  # KHZ
+]
+
+# tuples with command, regex pattern and conversion_factor to Hz
+FREQUENCY_COMMANDS = [
+    ("likwid-powermeter -i", r"Base clock:\s*([+-]?\d+(?:\.\d+)?)", 1e6)  # MHZ
+]
+
+
+def read_frequency_from_file(file_path: str) -> float:
+    """
+    Read the frequency value from a file.
+
+    Args:
+        file_path: The path to the file.
+
+    Returns:
+        The frequency value as a float.
+
+    Raises:
+        FileNotFoundError: If the file does not exist.
+        ValueError: If the file contains an invalid number.
+
+    """
+    try:
+        with open(file_path, "r") as file_handle:
+            return float(file_handle.read().strip())
+    except FileNotFoundError as e:
+        raise FileNotFoundError(f"File {file_path} not found") from e
+    except ValueError as e:
+        raise ValueError(f"Invalid number in file {file_path}") from e
+
+
+def run_command(command: str) -> str:
+    """
+    Runs a shell command and returns its output.
+
+    Args:
+        command: The shell command to run.
+
+    Returns:
+        The output of the command as a string.
+
+    Raises:
+        ValueError: If there is an error running the shell command.
+    """
+    try:
+        result = subprocess.run(
+            command,
+            shell=True,
+            capture_output=True,
+            text=True
+        )
+        return result.stdout.strip()
+
+    except subprocess.CalledProcessError as e:
+        raise ValueError(f"Error running command '{command}':\n{e.stderr}") from e
+
+
+def filter_output(pattern: str, output: str) -> str:
+    """
+    Filters the output of a command using a regex pattern.
+
+    Args:
+        pattern: The regex pattern to search for.
+        output: The output of the command as a string.
+
+    Returns:
+        The first match for the regex pattern in the output.
+
+    Raises:
+        LookupError: If no match is found for the regex pattern.
+    """
+    pattern = re.compile(pattern)
+    match = pattern.search(output)
+    if match:
+        return match.groups()[0]
+    else:
+        raise LookupError(f"No match found for pattern '{pattern}' in command output:\n{output}")
+
+
+def run_command_and_grep_output(command: str, grep_pattern: str) -> str:
+    """
+    Runs a shell command and greps the output for a regex pattern.
+
+    Args:
+        command: The shell command to run.
+        grep_pattern: The regex pattern to search for in the command output.
+
+    Returns:
+        The first match for the regex pattern in the command output.
+
+    Raises:
+        LookupError: If no match is found for the regex pattern.
+        ValueError: If there is an error running the shell command.
+
+    """
+
+    try:
+        output = run_command(command)
+        return filter_output(grep_pattern, output)
+    except subprocess.CalledProcessError as e:
+        raise ValueError(f"Error running command '{command}':\n{e.stderr}") from e
+
+
+def get_cpu_base_frequency(frequency_files=FREQUENCY_FILES, frequency_commands=FREQUENCY_COMMANDS) -> float:
+    """
+    Searches for the base CPU frequency in a list of files and returns it in GHz.
+
+    Args:
+        frequency_files (list of tuples): A list with tuples of frequency file paths and conversion factors.
+        frequency_commands (list of tuples): A list with tuples of commands, regex patterns, and conversion factors.
+
+    Returns:
+        The base CPU frequency in Hz as a float.
+
+    Raises:
+        ValueError: If the base CPU frequency cannot be determined.
+    """
+
+    for frequency_file, conversion_factor in frequency_files:
+        try:
+            frequency = read_frequency_from_file(frequency_file) * float(conversion_factor)
+            logger.info(f"Found CPU frequency in {frequency_file}: {frequency:.2f} Hz")
+            return frequency
+        except (FileNotFoundError, ValueError) as e:
+            logger.debug(f"Error reading CPU frequency from {frequency_file}: {e}")
+
+    for command, grep_pattern, conversion_factor in frequency_commands:
+        try:
+            frequency = float(run_command_and_grep_output(command, grep_pattern)) * float(conversion_factor)
+            logger.info(f"Found CPU frequency in {command} {grep_pattern}: {frequency:.2f} Hz")
+            return frequency
+        except (LookupError, ValueError) as e:
+            logger.debug(f"Error reading CPU frequency from {command} with {grep_pattern}: {e}")
+
+    raise ValueError("Unable to determine base CPU frequency")
+
+
+def main():
+    parser = argparse.ArgumentParser(description="Get the base CPU clock frequency in GHz")
+    parser.add_argument("-v", "--verbose", action="store_true", help="increase output verbosity")
+    args = parser.parse_args()
+
+    if args.verbose:
+        logging.basicConfig(level=logging.DEBUG)
+
+    frequency = get_cpu_base_frequency() / 1e9
+    print(f"{frequency:.2f}")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/setup.py b/setup.py
index 0b81b7340c70e918be36129df335d0305d303ac0..053944d769664d8e69f434b04ab2e0b3884bccec 100644
--- a/setup.py
+++ b/setup.py
@@ -10,6 +10,10 @@ setup(name="cb-util",
                                       "cbutil.postprocessing",
                                       "dashboards",
                                       "plotting"]),
+      entry_points={
+          'console_scripts':
+          'get_frequency = cbutil.cpu_frequency:main'
+      },
       install_requires=[
           "python-dotenv",
           "influxdb",