sysadmin · May 15, 2026 · 12 min read

Clean audit reports.
redirection, find, and pipes.

secadmin wants two clean reports off a base RHEL 9 box, and the real problem is not find. It is that nobody explained where the noise comes from.

// what we’re getting into
  1. The ticket
  2. How redirection actually works
  3. Set up the reports directory
  4. Report one. Recent .conf files.
  5. Report two. The SUID binary audit.
  6. More find filters worth knowing
  7. Pipe chains that answer real questions
  8. Hand the reports off
  9. Exam questions
  10. Final checklist: confirm everything works

The ticket: secadmin is running a compliance audit. They want every .conf file under /etc that changed in the last week, and a full list of the SUID binaries on the box for the security review. Their complaint is that every time they run find, half the screen fills with “Permission denied” and they cannot tell the real results from the noise.

The real problem: This is not a find bug. find is doing its job. The errors and the results are landing on the same terminal, so they look tangled together when they are actually on two separate streams. Once you see that, the fix is one small piece of redirection.

What we are doing: Learning I/O redirection, the find command, and pipes well enough to hand the security team two clean files. No extra packages, no new users, just base RHEL 9.

The ticket

Before anything else, confirm the ground you are standing on. Know who you are, and confirm the requester exists.

bash
whoami         # confirm you are your admin user
id secadmin    # confirm secadmin exists (UID 3501)

Concept review. How redirection works.

Start where you always start on this exam. The manual pages. These three cover everything the ticket touches, and the redirection section of the bash man page is the one to actually read.

bash
man bash    # then type /REDIRECTION to jump to that section
man find
man grep

Every command has two output streams. Standard output, called stdout, is file descriptor 1, and it carries the real results. Standard error, called stderr, is file descriptor 2, and it carries diagnostics like “Permission denied”. Both point at your terminal by default, which is exactly why they look mixed. They are not. You can send each one somewhere different.

These are the operators the whole ticket rests on. Lock them in.

the operators
'>'     send stdout to a file, overwriting whatever was there
'>>'    append stdout to a file instead of overwriting
'2>'    redirect stderr on its own
2>/dev/null   throw stderr away entirely
2>&1    send stderr wherever stdout is currently pointed
'&>'    shorthand for both streams at once (bash only)
'|'     feed stdout of one command into stdin of the next

Keep the results, bin the errors. That is the entire trick.

Set up the reports directory

Make a place for the deliverables before you generate them. You own it, the secops group can get in, nobody else can. 770 gives owner and group full access and everyone else nothing.

bash
sudo mkdir -p /srv/audit_reports
sudo chown admin:secops /srv/audit_reports
sudo chmod 770 /srv/audit_reports
ls -ld /srv/audit_reports

Report one. Recent .conf files.

Run it once with no redirection so you actually see the problem you are about to solve.

bash
find /etc -name "*.conf" -mtime -7

-mtime -7 means modified less than seven days ago. You get the files you want, salted with permission errors. Now split the streams. Real results into the report, errors into nowhere.

bash
find /etc -name "*.conf" -mtime -7 2>/dev/null > /srv/audit_reports/recent_conf.txt
cat /srv/audit_reports/recent_conf.txt
wc -l /srv/audit_reports/recent_conf.txt

The order of the two redirections does not matter here, because they point at different places. The file now holds only the answer.

Report two. The SUID binary audit.

A SUID binary runs with the privileges of its owner, not the person running it. That is why a system wide inventory is a standard security review artifact. This one needs sudo to see everything, and it is the same redirection pattern.

bash
sudo find / -perm /4000 -type f 2>/dev/null > /srv/audit_reports/suid_binaries.txt
wc -l /srv/audit_reports/suid_binaries.txt
head -10 /srv/audit_reports/suid_binaries.txt

-perm /4000 matches any file with the SUID bit set. You keep 2>/dev/null even with sudo, because /proc and /sys still throw errors you do not care about.

More find filters worth knowing

The exam leans on find constantly, so drill the filters until they are muscle memory. Every one of these is worth running.

bash
# by name
find /etc -name "sshd_config"

# by type, only regular files
find /var/log -type f -name "*.log" 2>/dev/null | head -5

# by modification time
find /etc -mtime -1 2>/dev/null    # changed in the last 24 hours
find /etc -mtime +30 2>/dev/null   # not touched in over 30 days

# by size
find /var -size +10M -type f 2>/dev/null | head -5

# by owner
sudo find / -user dbadmin1 2>/dev/null

# combined filters
find /etc -type f -name "*.conf" -size -10k -mtime -30 2>/dev/null | head -10

# run a command on each result
find /tmp -type f -name "*.txt" -exec ls -lh {} \; 2>/dev/null

Pipe chains that answer real questions

A pipe sends the clean stdout of one command into the next. Chained together they answer questions that would take real effort otherwise.

bash
# how many accounts use /bin/bash
cat /etc/passwd | grep "/bin/bash" | wc -l

# every shell in use, counted, most common first
cut -d: -f7 /etc/passwd | sort | uniq -c | sort -rn

# the five biggest log files
find /var/log -type f 2>/dev/null | xargs ls -lhS 2>/dev/null | head -5

# processes for a specific user
ps -u admin
ps aux | grep sshd | grep -v grep

Hand the reports off

Make the files readable by the secops group so they can pull them but not edit them, then prove the target user can actually read one.

bash
sudo chgrp secops /srv/audit_reports/*
sudo chmod 640 /srv/audit_reports/*
ls -l /srv/audit_reports/
sudo -u secadmin cat /srv/audit_reports/recent_conf.txt | head -5

Exam questions

Write the command before you run it. That is the only way it sticks.

Q1. Find every .log file under /var/log changed in the last 24 hours, suppress all permission errors, and save it to /srv/audit_reports/recent_logs.txt.

Q2. Count every file on the system owned by dbadmin1. Suppress errors and pipe the result through wc -l.

Q3. Explain why these two lines behave differently.

bash
ls /etc /fake > /tmp/out.txt 2>&1
ls /etc /fake 2>&1 > /tmp/out.txt

Answers.

bash
# A1
find /var/log -name "*.log" -mtime -1 2>/dev/null > /srv/audit_reports/recent_logs.txt
# A2
sudo find / -user dbadmin1 2>/dev/null | wc -l

A3. Redirections are read left to right. In the first line stdout is pointed at the file, then 2>&1 says send stderr wherever stdout now goes, which is the file, so both land in out.txt. In the second line 2>&1 runs while stdout is still the terminal, so stderr is nailed to the screen, and only then is stdout moved to the file. The errors print, only stdout gets saved. That ordering trap shows up constantly.

Final checklist: confirm everything works

If every check passes, the ticket is done.

bash
# 1. recent conf report exists and has content
wc -l /srv/audit_reports/recent_conf.txt

# 2. suid report exists and has content
wc -l /srv/audit_reports/suid_binaries.txt

# 3. secadmin can read the reports (group secops)
sudo -u secadmin cat /srv/audit_reports/recent_conf.txt | head

# 4. eyeball: you wrote all three exam commands before peeking
# 5. tracker entry checked off in Notion

Reply to secadmin: both reports are in /srv/audit_reports/, readable by the secops group. The permission errors were stderr, redirected to /dev/null on purpose, not suppressed by luck.

next post
Stable log references and catching broken symlinks before they rot