📝 psw_process_monitor.mdv4.4 · 2026-09-05

psw_process_monitor — Conversation Transcript

25/09/2026 · Andrew & Claude


i need a simple linuc command to let me see what a task/screen etc. is doing like LOAD, IO, CPU and MEMORU


Claude: [25/09/2026--22:27:27:566 AEST]

The simplest option is pidstat from the sysstat package. On CentOS 6 you can get it with yum install sysstat. It shows CPU, memory and disk I/O for one process, refreshed every N seconds:

pidstat -u -r -d -p <PID> 2

Adding load average: load is a figure for the whole machine, not for one process. To see it alongside, run:

watch -n2 "uptime; pidstat -u -r -d -p <PID> 1 1 | tail -n +3"

Finding the PID of something running inside a screen session:

screen -ls                      # shows e.g. 12345.mysession
pstree -p 12345 # lists the child processes and their PIDs

pidstat takes a comma-separated list, so you can watch several at once: -p 12346,12350.

If you don't want to install anything:


bets way to get the pid ?


Claude: [25/09/2026--22:30:38:411 AEST]

The simplest way is pgrep:

pgrep -f ISEmega
pidstat -u -r -d -p $(pgrep -f ISEmega | paste -sd,) 2

If more than one process matches, run this to see which is which:

ps -ef | grep [I]SEmega

The brackets around the first letter stop grep from listing itself. On CentOS 6 this is more reliable than pgrep -a, because the older procps there doesn't have that option.

For a screen session: use screen -ls to get the screen's PID, then run pstree -p <that PID>. That shows the actual job running inside it, which is the PID you want to monitor rather than the screen process itself.


make ps -ef | grep ISEmega into asinle command for me -= one that i vcan replace ISEmefda with whatever


Claude: [25/09/2026--22:32:44:370 AEST]

Add this line to your ~/.bashrc:

psg() { ps -ef | head -1; ps -ef | grep -i -- "$1" | grep -v grep; }

Then load it once with source ~/.bashrc. It will be available automatically in every new shell after that.

To use it:

psg ISEmega
psg httpd
psg python

now add pidtstat or what u thinmk is best


Claude: [25/09/2026--22:39:21 AEST]

Add this to your ~/.bashrc. I've kept the psg function from before and added a new one, psw, which watches whatever matches:

psg() { ps -ef | head -1; ps -ef | grep -i -- "$1" | grep -v grep; }
psw() { local p=$(pgrep -f -- "$1" | grep -vx "$$" | paste -sd,); [ -z "$p" ] && { echo "No process matching '$1'"; return 1; }; ps -o pid,etime,cmd -p "$p"; while ps -p "$p" >/dev/null; do echo; uptime; pidstat -h -u -r -d -p "$p" ${2:-2} 1 | grep -v -e '^Linux' -e '^$' -e '^Average'; done; echo "Process(es) ended."; }

Load it with source ~/.bashrc, then use it like this:

psw ISEmega        # refreshes every 2 seconds
psw rsync 5 # refreshes every 5 seconds

Stop it with Ctrl-C.

What it does:

  1. Finds every process whose command line matches the name.
  2. Lists those processes once, with how long each has been running.
  3. Then repeats on a loop:
    • Load: the uptime line, which gives the 1, 5 and 15-minute load averages.
    • CPU: %CPU.
    • Memory: RSS (real memory used, in KB) and %MEM.
    • I/O: kB_rd/s and kB_wr/s, plus iodelay if your version shows it.
  4. The -h option puts all of that on one line per process, instead of three separate tables.
  5. The loop stops by itself when the process ends.

I tested it here, but on a newer sysstat, so check these on your servers:


what is wron: scp /root/.bashrc 128.199.200.202:/Dev/root/.bashrc


Claude: [25/09/2026--23:00:05:108 AEST]

The problem is the remote path. /Dev/root/.bashrc means a folder called /Dev at the top of the remote disk, which doesn't exist. The part after the colon has to be a real path on the target machine, and you choose which machine by the IP, not the path:

scp /root/.bashrc 128.199.200.202:/root/.bashrc

That IP looks like a public cloud address, so check it's the machine you meant. If you meant the Dev VM, use Dev's IP or hostname in its place.

Also, this replaces the whole .bashrc on the other machine, including anything that exists only there (aliases, PATH changes and so on). If you only want to add the two new functions, append them instead of copying the file:

grep -E '^(psg|psw)\(\)' /root/.bashrc | ssh 128.199.200.202 'cat >> /root/.bashrc'

Log in to the other machine and run source ~/.bashrc once, or just open a new session.


no, that is correct - is the syntax ok ?


Claude: [25/09/2026--23:00:45:547 AEST]

Yes, the syntax is fine. The form is scp <local file> <host>:<remote path>, and that's what you have.

It will only work if these are true:

If it fails, the error message will say which one is the problem: "No such file or directory" means a missing folder, and "Permission denied" means a login or permissions issue.


 Dev root@dev:22:55:32:/bin# scp /root/.bashrc root@128.199.200.202:/Dev/root/.bashrc

This service is restricted to authorized System Administrator only. All activities on this system are logged. Unauthorized access will be fully investigated and reported to the appropriate law enforcement agencies.

/root/.bashrc: line 247: syntax error: unexpected end of file
.bashrc 100% 6057 5.9KB/s 00:00
 Dev root@dev:22:57:37:/bin#


Claude: [25/09/2026--23:02:02:655 AEST]

The copy worked (100% 6057). The error message comes from the Live machine's own /root/.bashrc, not from the file you just copied.

When scp logs in to 128.199.200.202, the shell there reads Live's /root/.bashrc. The file you sent went to /Dev/root/.bashrc, which is a different file. So Live's /root/.bashrc has a broken line near the end. "Unexpected end of file" means something opened was never closed, usually a { or a quote. The most likely cause is that the long psw line got wrapped or cut off when it was pasted into that file.

To confirm, run this on Live:

bash -n /root/.bashrc && echo OK      # checks the syntax without running anything
tail -5 /root/.bashrc # shows the last few lines

Fix: delete the broken psw line(s) on Live and paste this multi-line version instead. A long one-liner is easy to break when pasting; this version is much harder to damage:

psw() {
local p
p=$(pgrep -f -- "$1" | grep -vx "$$" | paste -sd,)
if [ -z "$p" ]; then echo "No process matching '$1'"; return 1; fi
ps -o pid,etime,cmd -p "$p"
while ps -p "$p" >/dev/null; do
echo; uptime
pidstat -h -u -r -d -p "$p" ${2:-2} 1 | grep -v -e '^Linux' -e '^$' -e '^Average'
done
echo "Process(es) ended."
}

Run bash -n /root/.bashrc again. It should print OK, and the warning will be gone from future scp and ssh logins.

Since the Dev copy came from the same paste, it's worth running bash -n /root/.bashrc on Dev too.


 Dev root@dev:22:57:37:/bin# brc
 Dev root@dev:22:58:28:/bin# bash -n /root/.bashrc
 Dev root@dev:22:58:30:/bin# scp /root/.bashrc root@128.199.200.202:/Dev/root/.bashrc

This service is restricted to authorized System Administrator only. All activities on this system are logged. Unauthorized access will be fully investigated and reported to the appropriate law enforcement agencies.

/root/.bashrc: line 247: syntax error: unexpected end of file
.bashrc 100% 6057 5.9KB/s 00:00
 Dev root@dev:22:58:48:/bin#


Claude: [25/09/2026--23:03:08:265 AEST]

That confirms it. bash -n printed nothing, which means Dev's .bashrc is clean. The error is in Live's /root/.bashrc, which runs every time you log in there, including through scp.

Run this from Dev to check Live's file without logging in interactively:

ssh root@128.199.200.202 'bash -n /root/.bashrc; tail -n 15 /root/.bashrc'

It will repeat the line-247 error, then show the last 15 lines of Live's file. Look for a psw or psg line that's been cut off or wrapped, or a { or quote with nothing closing it. Paste the output here if the cause isn't obvious and I'll point to the exact line.

Once you've found it, fix it on Live the usual way: remove the broken line(s) and use the multi-line psw from my last message. Then run bash -n /root/.bashrc on Live to confirm it's clean.


# Performance and Activy Monitoring -- eg.:
#
# psw ISEmega # refreshes every 2 seconds
# psw rsync 5 # refreshes every 5 seconds
#
# Stops with a "Ctrl-C"
#
psg() { ps -ef | head -1; ps -ef | grep -i -- "$1" | grep -v grep; }
psw() { local p=$(pgrep -f -- "$1" | grep -vx "$$" | paste -sd,); \
      [ -z "$p" ] && { echo "No process matching '$1'"; return 1; }; \
      ps -o pid,etime,cmd -p "$p"; while ps -p "$p" >/dev/null; \
      do echo; uptime; pidstat -h -u -r -d -p "$p" ${2:-2} 1 | \
      grep -v -e '^Linux' -e '^$' -e '^Average'; done; echo "Process(es) ended.$

exit 0


Claude: [25/09/2026--23:03:40:000 AEST]

There are two problems, and the second one matters more.

1. The last psw line is cut off. It ends with ended.$, so the closing "; } is missing. The quote is never closed, bash reads to the end of the file looking for it, and you get "unexpected end of file". The $ may also be your editor marking a line too long for the screen, but the error says the text really is cut off in the file.

2. Remove the exit 0 at the end of the file. Right now it's harmless only because the unclosed quote swallows it. Once you fix the quote, exit 0 will run on every login and close the shell straight away. That would break ssh logins and scp to that machine. A .bashrc should never end with exit.

To fix it, replace everything from psw() { down to and including exit 0 with this:

psw() {
local p
p=$(pgrep -f -- "$1" | grep -vx "$$" | paste -sd,)
if [ -z "$p" ]; then echo "No process matching '$1'"; return 1; fi
ps -o pid,etime,cmd -p "$p"
while ps -p "$p" >/dev/null; do
echo; uptime
pidstat -h -u -r -d -p "$p" ${2:-2} 1 | grep -v -e '^Linux' -e '^$' -e '^Average'
done
echo "Process(es) ended."
}

Keep your comment block and the psg line above it as they are. Then check it:

bash -n /root/.bashrc && echo OK

Keep your current session open while you test. Log in with ssh from a second terminal to make sure the login works before you close the first one.


look, just givbe a fuckiing batch file !


I've written fix_bashrc.sh and tested it on a copy of your broken block. It fixed the file, and psw then loaded normally. Run it on Live, either directly or from Dev with:

ssh root@128.199.200.202 'bash -s' < fix_bashrc.sh

It will still print the line-247 error once as it logs in, because the broken file is still in place at that point. After that it should say OK. If it doesn't, it puts your original file back automatically.

It backs up your .bashrc first. Then it replaces the broken psw lines and the exit 0 with the multi-line version, and leaves the rest of the file alone.


yeah, wher the fuck is it then ?


[Attached file: fix_bashrc.sh — contents in Appendix A]

Claude: [25/09/2026--23:11:07:513 AEST]

Sorry, I wrote the file but never actually sent it to you. It's attached now as fix_bashrc.sh.

Save it on Dev, then run it against Live from Dev:

ssh root@128.199.200.202 'bash -s' < fix_bashrc.sh

You'll see the line-247 error one last time as it logs in. Then it should print OK - /root/.bashrc fixed and passes syntax check. It backs up the old file first and restores it if the check fails.


NO ! fuck bashrc - just give me a bash script !


[Attached file: psw.sh — first version in Appendix B]

Claude: [25/09/2026--23:13:20:297 AEST]

psw.sh is ready in the outputs panel. It's a standalone script and doesn't touch .bashrc at all. I tested it here and it tracked a running process correctly. I haven't run it on CentOS 6 itself.

Install it on each machine:

cp psw.sh /usr/local/bin/psw
chmod +x /usr/local/bin/psw

Then run it the same way:

psw ISEmega
psw rsync 5

Stop it with Ctrl-C. It stops by itself when the process ends.

It matches anything whose command line contains the name. So an editor or screen session with "ISEmega" in its command will show up in the list as well.


thanks - so it lists everythig is no args ?


Claude: [25/09/2026--23:15:18:044 AEST]

No. With no arguments it just prints the usage line and exits:

Usage: /usr/local/bin/psw <name> [seconds]

I did that on purpose, because watching every process on the server with pidstat would flood the screen. If you want a no-argument mode, I'd have it show the top 10 processes by CPU, with memory and I/O, refreshing like the named mode does. Want me to add that?


but it flood the screen !


[Updated file: psw.sh — final version in Appendix C]

Claude: [25/09/2026--23:16:17:486 AEST]

Fixed. psw.sh now clears the screen and redraws in place on each refresh, the way top does, so it no longer scrolls. It also collects each sample before clearing, so the screen doesn't flicker blank while it waits. Long command lines are cut to your terminal width.

Copy the updated file over the old one in /usr/local/bin/psw on each machine.


hopw to clear a alias


Claude: [25/09/2026--23:19:12:460 AEST]

unalias name

That only lasts for your current shell. To remove it for good, also delete the alias name=... line from .bashrc.

Your old psg and psw are functions, not aliases, so unalias won't touch them. Use this instead:

unset -f psw psg

This matters here. While the old psw function is still loaded, typing psw runs the function instead of the new /usr/local/bin/psw script. To remove it permanently, delete the psg/psw lines from .bashrc on both machines. Then check which one runs:

type psw      # should say: psw is /usr/local/bin/psw

fuck this !


Claude: [25/09/2026--23:20:31:989 AEST]

Fair enough. The quickest way out is to skip the name clash entirely: install the script under a new name that nothing in .bashrc uses, so nothing needs cleaning up.

cp psw.sh /usr/local/bin/pmon
chmod +x /usr/local/bin/pmon

Then:

pmon ISEmega

That works right away, and the old psw lines can stay where they are.


type psw # should say: psw is /usr/local/bin/psw
psw is aliased to `'
 Dev root@dev:23:15:54:/bin#


Claude: [25/09/2026--23:20:38:606 AEST]

psw is now set up as an empty alias (probably from alias psw=''), and that hides the script. Remove it:

unalias psw
hash -r
type psw

It should now say psw is /usr/local/bin/psw. If it says psw is a function instead, also run unset -f psw.

If you put alias psw='' into .bashrc, delete that line too. Otherwise the empty alias comes back every time you log in.


 Dev root@dev:23:16:50:/bin# psw
/bin/psw: line 11: syntax error near unexpected token `then'
/bin/psw: line 11: `NAME="$1" INT="${2:-2}" if [ -z "$NAME" ]; then'
 Dev root@dev:23:16:52:/bin#


Claude: [25/09/2026--23:21:22:574 AEST]

When you pasted the script into /bin/psw, the line breaks were lost, so all the lines ran together into one. Here's a single command that installs the correct file without relying on pasting multiple lines. It writes the script to /usr/local/bin/psw, deletes the broken /bin/psw, and checks the result:

echo 'IyEvYmluL2Jhc2gKIyBwc3cuc2ggLS0gd2F0Y2ggTE9BRCwgQ1BVLCBNRU1PUlkgYW5kIEkvTyBmb3IgcHJvY2Vzc2VzIG1hdGNoaW5nIGEgbmFtZQojCiMgVXNhZ2U6ICBwc3cuc2ggPG5hbWU+IFtzZWNvbmRzXQojICAgcHN3LnNoIElTRW1lZ2EgICAgICAgICMgcmVmcmVzaGVzIGV2ZXJ5IDIgc2Vjb25kcwojICAgcHN3LnNoIHJzeW5jIDUgICAgICAgICMgcmVmcmVzaGVzIGV2ZXJ5IDUgc2Vjb25kcwojIFN0b3Agd2l0aCBDdHJsLUMuIFJ1biBhcyByb290IHRvIHNlZSBJL08gZm9yIG90aGVyIHVzZXJzJyBwcm9jZXNzZXMuCiMgTmVlZHMgcGlkc3RhdCAoeXVtIGluc3RhbGwgc3lzc3RhdCkuCgpOQU1FPSIkMSIKSU5UPSIkezI6LTJ9IgoKaWYgWyAteiAiJE5BTUUiIF07IHRoZW4KICBlY2hvICJVc2FnZTogJDAgPG5hbWU+IFtzZWNvbmRzXSIKICBleGl0IDEKZmkKCmNvbW1hbmQgLXYgcGlkc3RhdCA+L2Rldi9udWxsIHx8IHsgZWNobyAicGlkc3RhdCBub3QgZm91bmQgLSBydW46IHl1bSBpbnN0YWxsIHN5c3N0YXQiOyBleGl0IDE7IH0KCiMgRmluZCBtYXRjaGluZyBQSURzLCBza2lwcGluZyB0aGlzIHNjcmlwdCBpdHNlbGYgKGFuZCBpdHMgZmluaXNoZWQgc3Vic2hlbGxzKQpQSURTPSIiCmZvciBwaWQgaW4gJChwZ3JlcCAtZiAtLSAiJE5BTUUiKTsgZG8KICBbICIkcGlkIiA9ICIkJCIgXSAmJiBjb250aW51ZQogIGtpbGwgLTAgIiRwaWQiIDI+L2Rldi9udWxsIHx8IGNvbnRpbnVlCiAgUElEUz0iJHtQSURTOiskUElEUyx9JHBpZCIKZG9uZQoKaWYgWyAteiAiJFBJRFMiIF07IHRoZW4KICBlY2hvICJObyBwcm9jZXNzIG1hdGNoaW5nICckTkFNRSciCiAgZXhpdCAxCmZpCgp3aGlsZSBwcyAtcCAiJFBJRFMiID4vZGV2L251bGw7IGRvCiAgT1VUPSQocGlkc3RhdCAtaCAtdSAtciAtZCAtcCAiJFBJRFMiICIkSU5UIiAxIHwgZ3JlcCAtdiAtZSAnXkxpbnV4JyAtZSAnXiQnIC1lICdeQXZlcmFnZScpCiAgY2xlYXIKICBlY2hvICJwc3c6ICckTkFNRScgZXZlcnkgJHtJTlR9cyAgKEN0cmwtQyB0byBzdG9wKSIKICB1cHRpbWUKICBlY2hvCiAgcHMgLW8gcGlkLGV0aW1lLGNtZCAtcCAiJFBJRFMiIHwgY3V0IC1jMS0iJHtDT0xVTU5TOi0kKHRwdXQgY29scyAyPi9kZXYvbnVsbCB8fCBlY2hvIDE1MCl9IgogIGVjaG8KICBlY2hvICIkT1VUIgpkb25lCgplY2hvICJQcm9jZXNzKGVzKSBlbmRlZC4iCg==' | base64 -d > /usr/local/bin/psw && chmod +x /usr/local/bin/psw && rm -f /bin/psw && hash -r && bash -n /usr/local/bin/psw && echo INSTALLED-OK

When it prints INSTALLED-OK, you're set. I tested the same command here and it produced an exact copy of the script. Then run:

psw ISEmega

The same command works on Live.


what is going on? : Dev root@dev:23:19:55:/bin# lr psw*
ls: cannot access psw*: No such file or directory
 Dev root@dev:23:20:09:/bin# psw
Usage: /usr/local/bin/psw <name> [seconds]
 Dev root@dev:23:20:13:/bin#


Claude: [25/09/2026--23:24:51:489 AEST]

Everything is working. You're in /bin, and the installer deleted the broken /bin/psw, so there's no psw there for lr to find. The new copy is in /usr/local/bin/psw, which is the one that ran and printed the usage line (it's on your PATH).

To see it:

ls -l /usr/local/bin/psw

To use it, give it a process name:

psw ISEmega

ok, so how to simply install it everywhere ?


Claude: [25/09/2026--23:25:39:651 AEST]

Copy it from Dev with scp. For Live, it's one line:

scp -p /usr/local/bin/psw root@128.199.200.202:/usr/local/bin/psw

The -p keeps the file's permissions, so it stays executable. You'll still see the line-247 warning from Live's .bashrc, but the copy works.

If you have more machines, put them in a loop:

for h in 128.199.200.202 otherhost1 otherhost2; do scp -p /usr/local/bin/psw root@$h:/usr/local/bin/psw; done

Each machine needs pidstat. If a machine doesn't have it, the script will tell you to run yum install sysstat.


Build a MD and PDF transcript instructions: Transcribe the entire conversation, DO NOT EMBELLISH OR SUMMARISE UNLESS YOU FIRST HAVE IT VERBATIM, Expand all Query and Reply windows if applicable, Preserve formating, Embed any graphics, Do not lose a single word, Suggest a few names derived from a terse summary and pick the best but be as fast as possible.


Appendix A — fix_bashrc.sh

#!/bin/bash
# fix_bashrc.sh -- repairs the broken psw() block in /root/.bashrc
# Backs up the file, replaces psw() (and the trailing "exit 0") with a
# clean version, syntax-checks the result, and restores the backup if bad.

F=/root/.bashrc
B=$F.bak.$(date +%Y%m%d-%H%M%S)

cp -p "$F" "$B" || { echo "Backup failed - nothing changed."; exit 1; }
echo "Backup: $B"

# Remove from the psw() line down to "exit 0" (or to end of file if absent)
sed -i '/^psw()/,/^exit 0[[:space:]]*$/d' "$F"

cat >> "$F" <<'FUNC'
psw() {
local p
p=$(pgrep -f -- "$1" | grep -vx "$$" | paste -sd,)
if [ -z "$p" ]; then echo "No process matching '$1'"; return 1; fi
ps -o pid,etime,cmd -p "$p"
while ps -p "$p" >/dev/null; do
echo; uptime
pidstat -h -u -r -d -p "$p" ${2:-2} 1 | grep -v -e '^Linux' -e '^$' -e '^Average'
done
echo "Process(es) ended."
}
FUNC

if bash -n "$F"; then
echo "OK - $F fixed and passes syntax check."
else
cp -p "$B" "$F"
echo "Syntax check FAILED - original restored from $B."
exit 1
fi

Appendix B — psw.sh (first version, as delivered)

#!/bin/bash
# psw.sh -- watch LOAD, CPU, MEMORY and I/O for processes matching a name
#
# Usage: psw.sh <name> [seconds]
# psw.sh ISEmega # refreshes every 2 seconds
# psw.sh rsync 5 # refreshes every 5 seconds
# Stop with Ctrl-C. Run as root to see I/O for other users' processes.
# Needs pidstat (yum install sysstat).

NAME="$1"
INT="${2:-2}"

if [ -z "$NAME" ]; then
echo "Usage: $0 <name> [seconds]"
exit 1
fi

command -v pidstat >/dev/null || { echo "pidstat not found - run: yum install sysstat"; exit 1; }

# Find matching PIDs, skipping this script itself (and its finished subshells)
PIDS=""
for pid in $(pgrep -f -- "$NAME"); do
[ "$pid" = "$$" ] && continue
kill -0 "$pid" 2>/dev/null || continue
PIDS="${PIDS:+$PIDS,}$pid"
done

if [ -z "$PIDS" ]; then
echo "No process matching '$NAME'"
exit 1
fi

ps -o pid,etime,cmd -p "$PIDS"

while ps -p "$PIDS" >/dev/null; do
echo
uptime
pidstat -h -u -r -d -p "$PIDS" "$INT" 1 | grep -v -e '^Linux' -e '^$' -e '^Average'
done

echo "Process(es) ended."

Appendix C — psw.sh (final version, after the screen-clear update)

#!/bin/bash
# psw.sh -- watch LOAD, CPU, MEMORY and I/O for processes matching a name
#
# Usage: psw.sh <name> [seconds]
# psw.sh ISEmega # refreshes every 2 seconds
# psw.sh rsync 5 # refreshes every 5 seconds
# Stop with Ctrl-C. Run as root to see I/O for other users' processes.
# Needs pidstat (yum install sysstat).

NAME="$1"
INT="${2:-2}"

if [ -z "$NAME" ]; then
echo "Usage: $0 <name> [seconds]"
exit 1
fi

command -v pidstat >/dev/null || { echo "pidstat not found - run: yum install sysstat"; exit 1; }

# Find matching PIDs, skipping this script itself (and its finished subshells)
PIDS=""
for pid in $(pgrep -f -- "$NAME"); do
[ "$pid" = "$$" ] && continue
kill -0 "$pid" 2>/dev/null || continue
PIDS="${PIDS:+$PIDS,}$pid"
done

if [ -z "$PIDS" ]; then
echo "No process matching '$NAME'"
exit 1
fi

while ps -p "$PIDS" >/dev/null; do
OUT=$(pidstat -h -u -r -d -p "$PIDS" "$INT" 1 | grep -v -e '^Linux' -e '^$' -e '^Average')
clear
echo "psw: '$NAME' every ${INT}s (Ctrl-C to stop)"
uptime
echo
ps -o pid,etime,cmd -p "$PIDS" | cut -c1-"${COLUMNS:-$(tput cols 2>/dev/null || echo 150)}"
echo
echo "$OUT"
done

echo "Process(es) ended."