Grep and Loops
Author(s): Kirill Shore
Last Updated: 09-23-2025
Recommended Prerequisites (click to expand)
None
Definitions
Grep: a command-line utility for searching plain-text data for lines that match a given pattern.
What do we normally do when we need to find something? In typical GUI-based systems, the search bar is the main input. It can be used to find specific filetypes, or phrases within files, within the directory you are currently in. Grep serves that same purpose, but less user-friendly. It is simply like a search bar. For example: ls -al | grep hello is the same thing as typing hello into the search bar of your windows file explorer, it will simply find all files with hello on their titles (although windows also does the contents of the fies as well, I think). So, in the above command, we first listed all files (because grep only looks for things wihin a string, it doesn't just magically know you want to find files within a directory---for that you have to put your filter term in these quote thingies: ls -al | grep "hello") and then search that input for "hello", and printed all outputs with hello. Now, this may seem very basic, but in reality this is extremely useful. Linux doesn't have a simple "task manager" (depending on distro), so for many people, to do certain things requires grep. Grep is really good as a filter. Let's execute ps -ef as an example (don't worry about what it does for now):
kirillshore@Magma:~$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 00:30 ? 00:00:05 /sbin/init splash
nm-open+ 4308 4303 0 09:26 ? 00:00:04 /usr/sbin/openvpn --remote 79.127.185.165 80 udp --explicit-exit-notify --remote 79.127.185.165 51820 udp --explicit-exit-notify --remote 79.127.185.165 4569 udp
root 4579 2 0 09:26 ? 00:00:00 [psimon]
kirills+ 4589 1 16 09:26 ? 00:03:51 /snap/firefox/6738/usr/lib/firefox/firefox
kirills+ 4653 1 0 09:26 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/crashhelper 4589 9 /tmp/ 10 12
kirills+ 4695 1801 0 09:26 ? 00:00:00 /usr/libexec/xdg-desktop-portal
kirills+ 4704 1801 0 09:26 ? 00:00:01 /usr/libexec/xdg-desktop-portal-gtk
kirills+ 4753 4589 0 09:26 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -ipcHandle 0 -signalPipe 1 -initialChannelId {9344635f-1778-4e18-83fb-e8fe770c53d5} -parentPid 4589 -greo
kirills+ 4758 4753 0 09:26 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -parentBuildID 20250828192042 -prefsHandle 0:37119 -prefMapHandle 1:273460 -sandboxReporter 2 -chrootClie
kirills+ 4777 4753 3 09:26 ? 00:00:42 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:37260 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
kirills+ 4787 4753 0 09:26 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -parentBuildID 20250828192042 -prefsHandle 0:37260 -prefMapHandle 1:273460 -sandboxReporter 2 -chrootClie
kirills+ 4818 1801 0 09:26 ? 00:00:00 /usr/bin/snap userd
kirills+ 4982 4753 0 09:26 ? 00:00:01 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:46695 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
kirills+ 5299 4753 0 09:26 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -parentBuildID 20250828192042 -sandboxingKind 0 -prefsHandle 0:47645 -prefMapHandle 1:273460 -sandboxRepo
kirills+ 5317 4753 0 09:26 ? 00:00:06 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:43870 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
kirills+ 5471 4753 0 09:26 ? 00:00:06 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:43870 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
kirills+ 5582 4753 0 09:26 ? 00:00:02 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:44139 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
kirills+ 5632 4753 4 09:27 ? 00:00:56 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:44139 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
root 5912 2 0 09:29 ? 00:00:00 [kworker/1:2H]
kirills+ 6190 4753 3 09:31 ? 00:00:43 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:44197 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
kirills+ 6348 2120 0 09:31 ? 00:00:00 /usr/libexec/gvfsd-network --spawner :1.18 /org/gtk/gvfs/exec_spaw/2
kirills+ 6362 2120 0 09:31 ? 00:00:00 /usr/libexec/gvfsd-dnssd --spawner :1.18 /org/gtk/gvfs/exec_spaw/3
kirills+ 6374 1801 0 09:31 ? 00:00:00 python3 /usr/bin/wsdd --no-host --discovery --listen /run/user/1000/gvfsd/wsdd
root 6455 2 0 09:32 ? 00:00:02 [kworker/0:4-events]
root 6472 2 0 09:32 ? 00:00:00 [kworker/u8:0-ipv6_addrconf]
kirills+ 6529 2886 0 09:34 pts/2 00:00:00 bash
kirills+ 6603 1 0 09:36 ? 00:00:00 ssh-agent -s
root 6662 2 0 09:38 ? 00:00:00 [kworker/0:0-mm_percpu_wq]
root 6679 2 0 09:38 ? 00:00:00 [kworker/u9:1-i915_flip]
kirills+ 6695 4753 0 09:38 ? 00:00:04 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:44197 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
kirills+ 6756 4753 0 09:39 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:44197 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
root 6808 2 0 09:40 ? 00:00:00 [kworker/u8:1-cros_usbpd_log]
root 6843 2 0 09:41 ? 00:00:00 [kworker/1:2-i915-unordered]
kirills+ 6852 2886 0 09:41 pts/3 00:00:00 bash
root 6887 2 0 09:42 ? 00:00:00 [kworker/u9:2-i915_flip]
root 6980 2 0 09:45 ? 00:00:00 [kworker/0:1]
root 6983 2 0 09:45 ? 00:00:00 [kworker/1:0H-i915_cleanup]
root 6984 2 0 09:45 ? 00:00:00 [kworker/0:2H-kblockd]
root 7049 2 0 09:46 ? 00:00:00 [kworker/1:1-i915-unordered]
kirills+ 7050 6529 0 09:46 pts/2 00:00:00 nano grepandloops.md
kirills+ 7099 4753 0 09:48 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:44247 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
kirills+ 7129 4753 0 09:48 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -isForBrowser -prefsHandle 0:44247 -prefMapHandle 1:273460 -jsInitHandle 2:227036 -parentBuildID 20250828
root 7155 2 0 09:48 ? 00:00:00 [kworker/u8:2-events_unbound]
kirills+ 7182 6852 50 09:50 pts/3 00:00:00 ps -ef
We have several differen outputs for the command, but maybe the list is too long and we want to find commands for a specifc user, i.e. root. We can use grep as a filter by providing it the contents we want searched (ps -ef) and what we want to find (root)
kirillshore@Magma:~$ ps -ef | grep root
root 1 0 0 00:30 ? 00:00:05 /sbin/init splash
root 4579 2 0 09:26 ? 00:00:00 [psimon]
kirills+ 4758 4753 0 09:26 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -parentBuildID 20250828192042 -prefsHandle 0:37119 -prefMapHandle 1:273460 -sandboxReporter 2 -chrootClie
kirills+ 4787 4753 0 09:26 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -parentBuildID 20250828192042 -prefsHandle 0:37260 -prefMapHandle 1:273460 -sandboxReporter 2 -chrootClie
root 5912 2 0 09:29 ? 00:00:00 [kworker/1:2H]
root 6455 2 0 09:32 ? 00:00:02 [kworker/0:4-events]
root 6472 2 0 09:32 ? 00:00:00 [kworker/u8:0-ipv6_addrconf]
root 6662 2 0 09:38 ? 00:00:00 [kworker/0:0-mm_percpu_wq]
root 6679 2 0 09:38 ? 00:00:00 [kworker/u9:1-i915_flip]
root 6808 2 0 09:40 ? 00:00:00 [kworker/u8:1-cros_usbpd_log]
root 6843 2 0 09:41 ? 00:00:00 [kworker/1:2-i915-unordered]
root 6887 2 0 09:42 ? 00:00:00 [kworker/u9:2-i915_flip]
root 6980 2 0 09:45 ? 00:00:00 [kworker/0:1]
root 6983 2 0 09:45 ? 00:00:00 [kworker/1:0H-i915_cleanup]
root 6984 2 0 09:45 ? 00:00:00 [kworker/0:2H-kblockd]
root 7049 2 0 09:46 ? 00:00:00 [kworker/1:1-i915-unordered]
root 7155 2 0 09:48 ? 00:00:00 [kworker/u8:2-events_unbound]
Huh, that's weird. We used grep to look for root. Why do we have kirills+? The answer is simple: grep looks for ALL results. We told it to simply find root, and as we can see, the kirills+ line has the string "chrootClie" in it's output: kirills+ 4787 4753 0 09:26 ? 00:00:00 /snap/firefox/6738/usr/lib/firefox/firefox -contentproc -parentBuildID 20250828192042 -prefsHandle 0:37260 -prefMapHandle 1:273460 -sandboxReporter 2 -chrootClie This means that grep saw "root" in "chrootClie" and said: the user wanted to find all things with root, this countains root, so give the user this as an output as well.
But what if we want root search for simply a string, not a substring within a larger string? Well, simply put, we can add a -w flag. -w is short for the flag --word-regexp. this means it will "match only whole words" --- words that are by themselves.
kirillshore@Magma:~$ ps -ef | grep root -w
root 1 0 0 00:30 ? 00:00:05 /sbin/init splash
root 4579 2 0 09:26 ? 00:00:00 [psimon]
root 5912 2 0 09:29 ? 00:00:00 [kworker/1:2H]
root 6455 2 0 09:32 ? 00:00:02 [kworker/0:4-events]
root 6472 2 0 09:32 ? 00:00:00 [kworker/u8:0-ipv6_addrconf]
root 6662 2 0 09:38 ? 00:00:00 [kworker/0:0-mm_percpu_wq]
root 6679 2 0 09:38 ? 00:00:00 [kworker/u9:1-i915_flip]
root 6808 2 0 09:40 ? 00:00:00 [kworker/u8:1-cros_usbpd_log]
root 6843 2 0 09:41 ? 00:00:00 [kworker/1:2-i915-unordered]
root 6887 2 0 09:42 ? 00:00:00 [kworker/u9:2-i915_flip]
root 6980 2 0 09:45 ? 00:00:00 [kworker/0:1]
root 6983 2 0 09:45 ? 00:00:00 [kworker/1:0H-i915_cleanup]
root 6984 2 0 09:45 ? 00:00:00 [kworker/0:2H-kblockd]
root 7049 2 0 09:46 ? 00:00:00 [kworker/1:1-i915-unordered]
root 7155 2 0 09:48 ? 00:00:00 [kworker/u8:2-events_unbound]
as we can see, any lines that didn't contian root by itself were wiltered out.
Now, let's say that we have a file in which we need to find something. For example, we want to find all lines that mention 'sir'. However, the file is full of grammatical errors. Running the command like normal will not get all of the results we want:
kirillshore@Magma:~/GitHub/tmp$ cat romeo\ ampersand\ juliet\ chapter\ 1.md | grep sir
Abraham: Do you bite your thumb at us, sir?
Sampson: I do bite my thumb, sir.
Abraham: Do you bite your thumb at us, sir?
Sampson: No, sir. I do not bite my thumb at you, sir. But I bite my thumb, sir.
Abraham: Quarrel, sir! No, sir.
Sampson: If you do, sir, I am for you. I serve as good a man as you.
Sampson: Yes, better, sir.
This is where the -i flag comes in. The -i flag ensures that the output isn't case sensitive. This will result in the output returning both 'sir' and 'Sir':
kirillshore@Magma:~/GitHub/tmp$ cat romeo\ ampersand\ juliet\ chapter\ 1.md | grep -i sir
Abraham: Do you bite your thumb at us, sir?
Sampson: I do bite my thumb, sir.
Abraham: Do you bite your thumb at us, sir?
Sampson: No, sir. I do not bite my thumb at you, sir. But I bite my thumb, sir.
Gregory: Do you quarrel, Sir?
Abraham: Quarrel, sir! No, sir.
Sampson: If you do, sir, I am for you. I serve as good a man as you.
Sampson: Well, Sir.
Sampson: Yes, better, sir.