Twitter

How to use OCI Gen AI from the Linux command line

OCI Generative AI offers an on-demand service which you can access from your tenancy and pay only for what you use. This is very handy and also ensure that no data goes outside of the company if you were to copy/paste logs into whatever web based LLM. Integrating that capabilty into your daily hands-on work (analyze system state, diagnose issues, generate code, etc...) without ever leaving the terminal is a real productivity booster.
This is why I have developped a function which wraps the OCI CLI Generative AI Inference service that you can source and then call from the command line. You can download the full script from my GitHub repository.
Note that this is not meant to interact with your system, it cannot access your system.


Prerequisites: OCI Setup

Before using the function, you must have the OCI CLI installed and your OCI API keys configured on your system. If you haven't configured API keys yet, check out my step-by-step guide: OCI: Setting up API Keys.


Prerequisites: Compartment ID

You will need to set up your compartment ID inside the function:

DEF_COMP_ID="xxxxxxxxxx"
or export it from the command line before calling the function:
export ENV_COMP_ID="xxxxxxxxxx"
You may also adapt to your region:
export DEF_REGION="yyyyyyy"
or also export it from the command line before calling the function:
export ENV_REGION="us-phoenix-1"


Source the function and a first use

At the time I am writting this blog (Sep-2026), the function is set to use Grok 4.3 -- which can easily be updated into the function as well.
[frdenis@myvm ~]$ source .ai_functions"
[frdenis@myvm ~]$ source .ai_functions"
[frdenis@myvm ~]$ ask_llm "who are you ?"
I'm Grok, an AI built by xAI. I'm here to answer questions, help with problems, and have a bit of fun while doing it. What's up?
[frdenis@myvm ~]$


Storage Pressure Analysis (df)

First example is to check for space pressure on our system by seding the output of df -hto the LLM:
[frdenis@myvm ~]$ ask_llm "has this $(cat /etc/redhat-release) system some space pressure issue ? $(df -h)"
Based on the output, **no critical space pressure** at the moment, but there are a couple of areas worth monitoring:
### Summary
| Filesystem | Usage | Status |
|------------|-------|--------|
| `/` (root) | 61% | Moderate – fine for now |
| `/boot` | 68% | **Highest %** – monitor for kernel updates |
| `/data` | 39% | Healthy |
| `/run` (tmpfs) | 9% (4.1G used) | Using **4.1 GB of RAM** – worth checking |
### Recommendations
1. **`/boot` at 68%**
   This is the most "full" filesystem percentage-wise. If you install new kernels or if old ones aren't cleaned up, you could run into issues during updates. Consider removing old kernels if they're no longer needed.
2. **`/run` tmpfs using 4.1 GB**
   This is in-memory usage. If your system has memory constraints, investigate what's consuming that space:
   ```bash
   du -sh /run/* 2>/dev/null | sort -h
   ```
   Common culprits: large files in `/run/user/*`, container runtime data, or logs written to tmpfs.
3. **Root (`/`) at 61%**
   Not urgent, but if this system generates a lot of logs or temporary data, keep an eye on it.
**Bottom line:** No immediate crisis, but clean up `/boot` and check what's using 4.1 GB in `/run`.


SAR

We can also send the last 7 days of SAR for a quick summary / find potential issues:
[frdenis@myvm ~]$ ask_llm "check if this system has cpu issue, also let me know when are the cpu peaks: $(for i in {1..7}; do sar -u -f /var/log/sa/sa$(date -d "$i days ago" +%d); done)"
**Analysis Summary**
### Overall Assessment
**No significant CPU issue** on this system.
- The system has **16 CPUs** and is very lightly loaded on average.
- Average CPU utilization across all days is only **~10-11%** busy (`100% - 89% idle`).
- `%iowait` and `%steal` are negligible, which is good.
### CPU Usage Pattern
| Metric          | Average | Typical Range | Notes |
|-----------------|---------|---------------|-------|
| **%user**       | ~3.9%   | 0.3 – 24%     | Main driver of spikes |
| **%system**     | ~6.8%   | 6.0 – 8.7%    | Stable |
| **%idle**       | ~89%    | 68 – 93%      | Very healthy |
| **Total busy**  | ~11%    | -             | Low load |
### When CPU Peaks Occur
The system shows **very consistent daily patterns**:
| Time              | Typical Peak | %user | Total Busy | Frequency | Notes |
|-------------------|--------------|-------|------------|---------|-------|
| **12:00 PM – 12:10 PM** | **Highest** | 18–24% | **~25–31%** | Every day | **Main peak** |
| **07:10 AM – 07:20 AM** | High        | 10–17% | ~18–25%    | Every day | Morning spike |
| **11:10 AM, 11:50 AM**  | Medium      | 8–13%  | ~15–20%    | Frequent | - |
| **02:40 PM – 03:10 PM** | Medium      | 7–11%  | ~15–20%    | Frequent | - |
| **02:40 AM – 03:10 AM** | Medium      | 7–13%  | ~15–22%    | Occasional | Night spike |
### Key Observations
- **Biggest and most consistent peak**: **12:00 PM – 12:10 PM** every day (reaches ~30% CPU).
. . .


A quick shell command

We can also generate some code:
[frdenis@myvm ~]$ ask_llm "bash how to find the top 5 biggest files in my directories ?"
Here's the most common and effective way to find the **top 5 largest files** in a directory (including subdirectories):
### From current directory:
```bash
find . -type f -exec du -h {} + 2>/dev/null | sort -rh | head -5
```
### From root (entire system) — requires `sudo`:
```bash
sudo find / -type f -exec du -h {} + 2>/dev/null | sort -rh | head -5
```
### Alternative (faster, shows size in bytes):
```bash
find . -type f -printf '%s %p\n' | sort -rn | head -5
```
### Explanation:
| Command part | Purpose |
|--------------|--------|
| `find . -type f` | Find only files (ignore directories) |
| `-exec du -h {} +` | Get human-readable sizes |
| `sort -rh` | Sort by size, reverse (largest first), human-readable |
| `head -5` | Show only top 5 |
### Tip:
If you want to **exclude certain directories** (like `/proc`, `/sys`, etc.), you can do:
```bash
sudo find / -path /proc -prune -o -path /sys -prune -o -type f -exec du -h {} + 2>/dev/null | sort -rh | head -5
```
It is also very useful for crash diagnosis using /var/log/messages, etc... possibilities are endless. Test it and enjoy!

Some bash tips -- 19 -- A generic pretty table output function

Output is key to present our findings and this is even more important in Bash as, for most people, all of this is just raw text on a geek black and white terminal. Also we have to admit that it oftenly takes more time to make a pretty output than to collect the data we are interested in so the output formatting is often treated as an afterthought. I have already shown how to get a nice output using column, all of my scripts have nice outputs but they are specific and the formatting needs to be redone for each script.
This is why I came up with a generic function formatting data from arrays which I have been using for a while now. I will just be using the first 5 lines of a generic /etc/passwd file as an example below.


Sourcing the Script

The idea is to keep this function in a dedicated file (let's name it print_table.sh) and then source it when you need it.
[frdenis@myvm ~]$ source print_table.sh
[frdenis@myvm ~]$


Preparing the data

The print_table() function expects a Bash array of comma-separated strings (CSV style). The first element of the array (index 0) is always treated as the header row.
Let's take the first 5 lines of /etc/passwd as our data source:
[frdenis@myvm ~]$ head -5 /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
[frdenis@myvm ~]$


Basic Table Usage

To render this as a table, we construct a Bash array, define our header as the first element, replace the ":" delimiters with commas "," and pass the array by reference:
source ./print_table.sh
# Initialize array and create data[0] which is our table header
data=("Username,Password,UID,GID,Comment,Home,Shell")

# Read /etc/passwd line by line and append into the ""data" array
while IFS= read -r line; do
    data+=("$(echo "$line" | tr ':' ',')")
done < <(head -5 /etc/passwd)

# Print the table
print_table data

| Username | Password | UID |  GID  | Comment |   Home    |       Shell       |
------------------------------------------------------------------------------
|   root   |    x     |  0  |   0   |  root   |   /root   |     /bin/bash     |
|  daemon  |    x     |  1  |   1   | daemon  | /usr/sbin | /usr/sbin/nologin |
|   bin    |    x     |  2  |   2   |   bin   |   /bin    | /usr/sbin/nologin |
|   sys    |    x     |  3  |   3   |   sys   |   /dev    | /usr/sbin/nologin |
|   sync   |    x     |  4  | 65534 |  sync   |   /bin    |     /bin/sync     |
------------------------------------------------------------------------------


Customizing Alignment & Row Count

By default, all column contents are centered. You can customize alignment per column by passing a second array containing positional alignment codes:
  • l : Left alignment
  • c : Center alignment (default)
  • r : Right alignment
You can also display the total number of processed rows at the bottom by setting L_SHOW_TOTAL="True".
[frdenis@myvm ~]$ cat demo_align.sh
#!/bin/bash
source ./print_table.sh

data=("Username,Password,UID,GID,Comment,Home,Shell")
while IFS= read -r line; do
    data+=("$(echo "$line" | tr ':' ',')")
done < <(head -5 /etc/passwd)

# Define column alignments: Left, Center, Right, Right, Left, Left, Left
align=("l" "c" "r" "r" "l" "l" "l")

# Enable total row count display
export L_SHOW_TOTAL="True"

print_table data align
[frdenis@myvm ~]$ ./demo_align.sh

| Username | Password | UID |   GID | Comment | Home      | Shell             |
----------------------------------------------------------------------------------
| root     |    x     |   0 |     0 | root    | /root     | /bin/bash         |
| daemon   |    x     |   1 |     1 | daemon  | /usr/sbin | /usr/sbin/nologin |
| bin      |    x     |   2 |     2 | bin     | /bin      | /usr/sbin/nologin |
| sys      |    x     |   3 |     3 | sys     | /dev      | /usr/sbin/nologin |
| sync     |    x     |   4 | 65534 | sync    | /bin      | /bin/sync         |
----------------------------------------------------------------------------------
Number of rows: 5
[frdenis@myvm ~]$


Generating Value Summaries (Comma Lists)

A unique feature of this function is the ability to automatically generate comma-separated summaries of specific columns beneath the table. This is very useful when you want to feed list outputs directly into subsequent script commands or quickly copy/paste them.
Pass the 1-based column indices as parameter 3, and an optional row limit as parameter 4:
[frdenis@myvm ~]$ cat demo_summary.sh
#!/bin/bash
source ./print_table.sh

data=("Username,Password,UID,GID,Comment,Home,Shell")
while IFS= read -r line; do
    data+=("$(echo "$line" | tr ':' ',')")
done < <(head -5 /etc/passwd)

# Request summary list for Column 1 (Usernames) and Column 3 (UIDs), max 3 rows
print_table data "" "1,3" 3
[frdenis@myvm ~]$ ./demo_summary.sh

| Username | Password | UID | GID   | Comment | Home      | Shell             |
----------------------------------------------------------------------------------
|   root   |    x     |  0  |   0   |  root   |   /root   |     /bin/bash     |
|  daemon  |    x     |  1  |   1   | daemon  | /usr/sbin | /usr/sbin/nologin |
|   bin    |    x     |  2  |   2   |   bin   |   /bin    | /usr/sbin/nologin |
|   sys    |    x     |  3  |   3   |   sys   |   /dev    | /usr/sbin/nologin |
|   sync   |    x     |  4  | 65534 |  sync   |   /bin    |     /bin/sync     |
----------------------------------------------------------------------------------

Username values (up to 3): root,daemon,bin
UID values (up to 3): 0,1,2

[frdenis@myvm ~]$

Scripting Integration: RAW Output Mode

When passing data downstream in pipeline operations, ASCII borders can get in the way. You can bypass the table rendering entirely by enabling L_RAW="True". This outputs the raw array content without borders or alignments:
[frdenis@myvm ~]$ L_RAW="True" ./demo.sh
Username,Password,UID,GID,Comment,Home,Shell
root,x,0,0,root,/root,/bin/bash
daemon,x,1,1,daemon,/usr/sbin,/usr/sbin/nologin
bin,x,2,2,bin,/bin,/usr/sbin/nologin
sys,x,3,3,sys,/dev,/usr/sbin/nologin
sync,x,4,65534,sync,/bin,/bin/sync
[frdenis@myvm ~]$
Pro Tip: Using L_RAW="True" makes your scripts dual-purpose. They can produce human-friendly interactive CLI tables by default, or clean CSV data when piped into other tools.



< Previous shell tip / Next shell tip coming soon >

Python venv

A lot of application running on our VMs use python. As python evolves a lot and is extensible through modules, it is very frequent that a user do not have the correct modules / modules versions he needs for his project.
To keep it clean and flexible, we do not want to install python packages at the system level, we want each non-privileged user to be using python virtual environment. Note that the base python version requested by the user will need to be installed at the system level.


Proxy

Depending on your company, you may need a proxy to be able to install any python version or module:
export https_proxy=http://www-proxy-your_company.com:80


Example

Below example will be using a non-privileged user "frdenis" on the myvm VM.
[frdenis@myvm ~]$ id
uid=1003(frdenis) gid=1003(frdenis) groups=1003(frdenis) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[frdenis@myvm ~]$
The default python of the system is 3.6.8:
[opc@myvm ~]$ python -V
Python 3.6.8
[opc@myvm ~]$
Python 3.11 will need to be installed as the example will showcase a python3.11 virtual environment:
[opc@myvm ~]$ sudo dnf install -y python3.11 python3.11-pip
. . .
[opc@myvm ~]$ python3.11 -V
Python 3.11.13
[opc@myvm ~]$


Python venv


Check the system python

[frdenis@myvm ~]$ type python
python is /usr/bin/python
[frdenis@myvm ~]$ /usr/bin/python --version
Python 3.6.8
[frdenis@myvm ~]$

Create and activate a venv

We will name this virtual environment "venv" in this example which is the usage.
[frdenis@myvm ~]$ python -V
Python 3.6.8
[frdenis@myvm ~]$ python3.11 -m venv venv             <== the second "venv" is the name of your venv
[frdenis@myvm ~]$ source venv/bin/activate
(venv) [frdenis@myvm ~]$ python -V            <== note that starting "(venv)" showing you are IN the virtual env
Python 3.11.13
(venv) [frdenis@myvm ~]$

Install packages in the venv

Once the venv activated, we can install any module we want in it and as our non-privileged user:
(venv) [frdenis@myvm ~]$ python
Python 3.11.13 (main, Apr 27 2026, 16:44:16) [GCC 8.5.0 20210514 (Red Hat 8.5.0-28.0.1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy                               <== numpy is not default
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'numpy'
>>> quit()
(venv) [frdenis@myvm ~]$ export https_proxy=http://www-proxy-hqdc.us.oracle.com:80
(venv) [frdenis@myvm ~]$ pip install numpy
Collecting numpy
  Downloading numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (16.9 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 16.9/16.9 MB 9.2 MB/s eta 0:00:00
Installing collected packages: numpy
Successfully installed numpy-2.4.6
[notice] A new release of pip available: 22.3.1 -> 26.2.1
[notice] To update, run: pip install --upgrade pip
(venv) [frdenis@myvm ~]$ python
Python 3.11.13 (main, Apr 27 2026, 16:44:16) [GCC 8.5.0 20210514 (Red Hat 8.5.0-28.0.1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>>

Showcase

Let's write a simple python script using numpy:
[frdenis@myvm ~]$ cat test_env.py
import sys
import numpy as np
print("Python Version :", sys.version.split()[0])
print("Numpy Version  :", np.__version__)
print("Numpy Test     :", np.array([10, 20, 30]) * 2)
[frdenis@myvm ~]$
It works in the venv:
(venv) [frdenis@myvm ~]$ python test_env.py
Python Version : 3.11.13
Numpy Version  : 2.4.6
Numpy Test     : [20 40 60]
(venv) [frdenis@myvm ~]$
But not outside of the venv (as numpy is not default) and has only been installed in the venv:
(venv) [frdenis@myvm ~]$ deactivate
[frdenis@myvm ~]$ python test_env.py
Traceback (most recent call last):
  File "test_env.py", line 2, in <module>
    import numpy as np
ModuleNotFoundError: No module named 'numpy'
[frdenis@myvm ~]$


Automatically use the venv

As it may not be nice to source the venv each time we want to run a python script (from a shell for example), 2 solutions exist for that:

Run the script using the venv python

[frdenis@myvm ~]$ ~/venv/bin/python test_env.py
Python Version : 3.11.13
Numpy Version  : 2.4.6
Numpy Test     : [20 40 60]
[frdenis@myvm ~]$

Use a shebang which points to the venv

[frdenis@myvm ~]$ cat test_env.py
#!/home/frdenis/venv/bin/python                             <== here, this is the shebang, adapt to your path
import sys
import numpy as np
print("Python Version :", sys.version.split()[0])
print("Numpy Version  :", np.__version__)
print("Numpy Test     :", np.array([10, 20, 30]) * 2)
[frdenis@myvm ~]$ chmod u+x test_env.py                   <== has to be done only once when setting it up
[frdenis@myvm ~]$ ./test_env.py
Python Version : 3.11.13
Numpy Version  : 2.4.6
Numpy Test     : [20 40 60]
[frdenis@myvm ~]$


Transfer a venv to another user/machine

Note: Do NOT copy the "venv" directory to another user or machine, it contains hardcoded absolute paths and machine specifics which wont make it work.

Export the module list

[frdenis@myvm ~]$ source venv/bin/activate
(venv) [frdenis@myvm ~]$ pip freeze > requirements.txt
(venv) [frdenis@myvm ~]$ cat requirements.txt
numpy==2.4.6
(venv) [frdenis@myvm ~]$

Re-apply to another virtual env

Once this requirements.txt file has been transferred:
[new_user@another_vm ~]$ python3.11 -m venv new_venv             <== create a new venv
[new_user@another_vm ~]$ source new_venv/bin/activate            <== activate the new venv
[new_user@another_vm ~]$ pip install -r requirements.txt         <== reinstall the modules from the original venv
. . .
[new_user@another_vm ~]$

How to use OCI Gen AI from the Linux command line

OCI Generative AI offers an on-demand service which you can access from your tenancy and pay only for what you use. This is very handy and...