home / tils / til

Menu
  • GraphQL API

til: bash_nullglob-in-bash.md

This data as json

path topic title url body html shot created created_utc updated updated_utc shot_hash slug
bash_nullglob-in-bash.md bash nullglob in bash https://github.com/simonw/til/blob/main/bash/nullglob-in-bash.md I ran into a tricky problem while working [on this issue](https://github.com/simonw/datasette-publish-fly/issues/17): the following line was behaving in an unexpected way for me: datasette content.db *.db --create What I expect this to do is to create a `content.db` database if one does not exist, and then start Datasette with both that database and any other databases that exist in the directory. The surprising behaviour occurred when the directory started off empty. Running the above in `bash` caused a file called `*.db` to be created in the directory. It turns out if `bash` can't find any files matching a wildcard it passes that wildcard as a literal value to the underlying command! `sh` does the same thing. `zsh` returns an error: ``` % datasette content.db *.db --create zsh: no matches found: *.db ``` The solution, for `bash`, is to set the `nullglob` shell option. That can be done like this: shopt -s nullglob This lasts for the rest of the interactive session, and causes `bash` to behave the way I expected it to, completely ignoring the `*.db` wildcard if it has no matches. ## Using this in a Dockerfile I originally ran into this because I had a `Dockerfile` with a last line that looked like this: `CMD datasette serve --host 0.0.0.0 --cors --inspect-file inspect-data.json --metadata metadata.json /data/tiddlywiki.db --create --port $PORT /data/*.db` The goal here was to serve any existing databases in the `/data/` mounted volume, and to explicitly create that `tiddlywiki.db` database if it did not exist. But it created a `*.db` database file if the folder was empty, due to the issue described above. I ended up using this recipe to work around the problem: `CMD ["/bin/bash", "-c", "shopt -s nullglob && datasette serve --host 0.0.0.0 --cors --inspect-file inspect-data.json /data/tiddlywiki.db --create --port $PORT /data/*.db"]` This uses `CMD` to execute `/bin/bash` and pass it a one-liner that sets `nullglob` and then calls Datasette. This worked as intended. <p>I ran into a tricky problem while working <a href="https://github.com/simonw/datasette-publish-fly/issues/17">on this issue</a>: the following line was behaving in an unexpected way for me:</p> <pre><code>datasette content.db *.db --create </code></pre> <p>What I expect this to do is to create a <code>content.db</code> database if one does not exist, and then start Datasette with both that database and any other databases that exist in the directory.</p> <p>The surprising behaviour occurred when the directory started off empty. Running the above in <code>bash</code> caused a file called <code>*.db</code> to be created in the directory.</p> <p>It turns out if <code>bash</code> can't find any files matching a wildcard it passes that wildcard as a literal value to the underlying command!</p> <p><code>sh</code> does the same thing. <code>zsh</code> returns an error:</p> <pre><code>% datasette content.db *.db --create zsh: no matches found: *.db </code></pre> <p>The solution, for <code>bash</code>, is to set the <code>nullglob</code> shell option. That can be done like this:</p> <pre><code>shopt -s nullglob </code></pre> <p>This lasts for the rest of the interactive session, and causes <code>bash</code> to behave the way I expected it to, completely ignoring the <code>*.db</code> wildcard if it has no matches.</p> <h2> <a id="user-content-using-this-in-a-dockerfile" class="anchor" href="#using-this-in-a-dockerfile" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Using this in a Dockerfile</h2> <p>I originally ran into this because I had a <code>Dockerfile</code> with a last line that looked like this:</p> <p><code>CMD datasette serve --host 0.0.0.0 --cors --inspect-file inspect-data.json --metadata metadata.json /data/tiddlywiki.db --create --port $PORT /data/*.db</code></p> <p>The goal here was to serve any existing databases in the <code>/data/</code> mounted volume, and to explicitly create that <code>tiddlywiki.db</code> database if it did not exist.</p> <p>But it created a <code>*.db</code> database file if the folder was empty, due to the issue described above.</p> <p>I ended up using this recipe to work around the problem:</p> <p><code>CMD ["/bin/bash", "-c", "shopt -s nullglob &amp;&amp; datasette serve --host 0.0.0.0 --cors --inspect-file inspect-data.json /data/tiddlywiki.db --create --port $PORT /data/*.db"]</code></p> <p>This uses <code>CMD</code> to execute <code>/bin/bash</code> and pass it a one-liner that sets <code>nullglob</code> and then calls Datasette. This worked as intended.</p> <Binary: 64,398 bytes> 2022-02-14T21:16:05-08:00 2022-02-15T05:16:05+00:00 2022-02-14T21:16:05-08:00 2022-02-15T05:16:05+00:00 617dfd393565706d61b6bf41b1401c65 nullglob-in-bash
Powered by Datasette · How this site works · Code of conduct