> ## Content Index
> Fetch the complete content index at: https://www.workroom-productions.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Tiny Tool: checkRefs.sh
- URL: https://www.workroom-productions.com/tiny-tool-checkrefs-sh/
- Published: 2025-07-16T13:56:25.000Z
- Updated: 2025-11-25T22:35:20.000Z
- Description: A tiny tool to see which files include one or more of a set of strings.
- Author: James Lyndsay
- Tags: tiny tool, Articles

#### Addendum: why not `xargs`?

Why not, indeed? I revisited this tiny tool as I built a short workshop on `xargs` and rethought (again, with an LLM). This one-liner is the end product:

`ls -1 ./templates | xargs -I{} sh -c 'echo "## {}"; grep -Flsir "{}" ./* ' `

That substitutes the shell script below for

`xargs -I{} sh -c 'echo "## {}"; grep -Flsir "{}" ./* '`

What does this do?

- `ls -1 ./templates` makes a list of the filenames in the `templates` directory
- `|` sends the list to xargs
- `xargs -I{} sh -c` works through that list of filenames, runs the shell script in the single quotes `'...'`, and substitutes any `{}` in the shell script for the filename.
- `echo "## {}";` Sends the filename prefixed with `##` to the terminal
- `grep -Flsir "{}" ./* '` seeks the filename in any of the files in the current directory, with `-Flsi` options as below. Note the new `r` recursive option, so it track tracks down the hierarchy, and the starting point and pattern `./`**.* I could use `.` for the current directory, but this pattern lets me change directories up (`../`) and down (`./target/*`). At the moment, this picks up the template directory, too.

```bash
while read -r referenced_String; do
    matches=$(grep -Flsi "$referenced_String" *)
    echo "## ${referenced_String}"
    if [ -n "$matches" ]; then
        echo "$matches"
    else
        echo "unreferenced"
    fi
done
```

Used with `ls -1 ./templates | sh ./checkRefs.sh`, this will check the files in the current directory to see which ones use a file from `templates`

To try it out, clone this for an example set of files, the shell script and command. <https://github.com/workroomprds/template%5Flists%5Fexample>

#### command

`sudo git clone `<https://github.com/workroomprds/template%5Flists%5Fexample>

I used this when building playbooks, to see which templates were used by files in the current directory – and which were unused. If a file referenced two templates, I could see that, too. 

I built the tool because I did the work by hand a couple of times, and that became slow and error-prone as the number of files and strings increased. I couldn't find a way to make a tool (either on the commandline or within my IDE) do it. So it's tool time. Making it took about 15 minutes, and taught me some stuff – time well spent. Writing about making it has taken an hour.

I imagine I'll use it generally: I'll certainly use it on my current project again.

Subscribers get to see how I used LLMs Qwen3 and Claude3.7Sonnet.

## Building

I built it / breathed it into existence by asking Qwen3 (local, thinking) and Claude3.7 (cloud, powerful, thinking off). 

- Qwen3 ended up with a script close to the one above.
- Claude3.7 built something more robust, with better output, but a bit harder to read.
- I took Qwen's, added the "unreferenced" from Claude and a `grep` option, and fiddled the `referenced_String` to help me understand next time.

I checked its output against something I'd already done by hand – it matched. To check that a string referenced multiple times turned up several times, and at the same time checking the behaviour for a file referencing several strings (which wasn't going to be checked by the set I was using by hand), I temporarily popped a file listing of the `templates` directory into the current directory – so *every* string was in twice, and one file had them all. That took less time to do than to describe, and worked to my satisfaction.

## Details of prompting

The prompt I used started with was :

```text
Given a list of strings (i.e. a file of newline-delimited filenames) I want to search through a directory of files to see where those filenames are used, and whether any filename is unused.
```

I had a couple of conversations with Qwen, which was fixating on seeing what files were in both directories, and got very confused in its thinking (particularly with a list of filenames to search in a list of named files). Those conversations helped me to refine by asking for a shell script, by clarifying the difference between the strings to be searched for and the files to search, and by clarifying the way I'd use it in terms of input and output. Watching Qwen also gave me time to pause and think – but it's a mistake to imagine that one's thinking is improved while watching an LLM chew its own tail. 

The eventual conversation starting prompt ended up being: 

```text
Given a list of strings (i.e. a file of newline-delimited filenames) I want to search through a directory of files to see which files contain those strings/filenames, and whether any string/filename is unused. I want a shell script, taking stdin as input. I will probably pipi ls -1 to the input. I want the output organised (for now) by the input list in the form ## «string»
```

For this, Qwen got (literally) lost in thought over several minutes. It eventually output code in its 'think' response, threw up into the conversation title (weird...) and failed to output anything else at all. But the code looked OK.

I ran the same prompt with Claude3.7Sonnet, which gave me 50+ lines of guff. I asked several times to make the offered code terse and readable: by using `grep` rather than `find`, by *removing* robustness, by *removing* a "count" function, and by *removing* bullet points in the output. I asked it to compare its eventual output with Qwen's / mine, and it outlined differences that... led me back to the simpler one.

I say "simpler", but the `grep -Flsi` bit is complex, and more complex than suggested by either. Qwen went for `grep -Fls`, Claude went even simpler but did suggest `-i` to make the command case-insensitive (I want to see if something's used, not if it's used well, so that's better). I can imagine that I'll wonder what they meant, and I imagine I'll ask an LLM, so...

Here's Claude to explain:

#### In bullet points, talk me through the options used in `grep -Flsi`

- ****F**: ****Fixed strings** \- Treats the pattern as a fixed string rather than a regular expression. This means special regex characters like `.`, `*`, `[`, etc. are treated literally.
- ****l**: ****List filenames only** \- Instead of showing the matching lines, grep only outputs the names of files containing matches. Each filename is printed once, even if multiple matches exist in the file.
- ****s**: ****Suppress error messages** \- Silences error messages about nonexistent or unreadable files. Useful for avoiding error output when grep encounters permission issues or other errors.
- ****i**: ****Case-insensitive** \- Makes the search ignore case differences between the pattern and the file contents. For example, searching for "hello" would match "Hello", "HELLO", etc.

Together, these options make grep return just the filenames where the exact string appears (ignoring case), without showing any error messages.

(LLM-generated content, judged reasonable by me)