# Something like \`grep -q String Filename\` in Julia?

**URL:** <https://discourse.julialang.org/t/something-like-grep-q-string-filename-in-julia/106959>\
**Category:** General Usage\
**Created:** [November 30, 2023, 5:32pm UTC](https://discourse.julialang.org/t/something-like-grep-q-string-filename-in-julia/106959 "2023-11-30T17:32:17Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 30, 2023, 5:32pm UTC](https://discourse.julialang.org/t/something-like-grep-q-string-filename-in-julia/106959/1 "2023-11-30T17:32:17Z")

</div>

Is there something similar to `grep -q Filename String` in Julia? Meaning, a command that just checks if a string is present in a text file and returns true or false?

Alternatively (this is actually what I need), is there a way to check if a JSON file has a field, without actually loading it into memory? I’m using JSON3 to read/write json files with nested structs, and I need to know if one o the nested structs has a specific field before reading the json file into the appropriate data structure.

---

<div class="post-metadata">

**Author:** ![dmbates](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dmbates/32/44_2.png) [@dmbates](https://discourse.julialang.org/u/dmbates)\
**Post date:** [November 30, 2023, 6:25pm UTC](https://discourse.julialang.org/t/something-like-grep-q-string-filename-in-julia/106959/2 "2023-11-30T18:25:18Z")

</div>

Would something like

```julia
julia> open("/etc/passwd", "r") do io
           contains(read(io, String), "Apple")
       end
true

```

suffice?

I guess that will read the whole file. Perhaps memory-mapping the file would be more effective on large files.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 30, 2023, 6:33pm UTC](https://discourse.julialang.org/t/something-like-grep-q-string-filename-in-julia/106959/3 "2023-11-30T18:33:33Z")

</div>

I have a single-line long file (that’s how the JSON3 package saves my struct). So now I’ve put the relevant field as the first field in the line, something like:

```julia
{"Version":"1.3.5-DEV","nbins":500,"dbulk":10.0,"cutoff"...

```

and I’m reading char-by-char (my goal is to get that version number), with:

```julia-repl
julia> function get_version(filename)
           i = 0
           str = ""
           file = open(filename, "r")
           while true
               c = read(file, Char)
               i += 1
               (c == ',' || i > 100) && break
               str = str*c
           end
           close(file)
           str = split(str, ":")
           v = if occursin("Version", str[1])
               parse(VersionNumber, string(str[2][begin+1:end-1]))
           else
               v"0.0.0" 
           end
           return v
       end

```

I think this is not reading the whole file in memory (let me know if I’m wrong). I’m open to better ideas as well.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 30, 2023, 7:25pm UTC](https://discourse.julialang.org/t/something-like-grep-q-string-filename-in-julia/106959/4 "2023-11-30T19:25:43Z")

</div>

> [@dmbates](#):
>
> Perhaps memory-mapping the file would be more effective on large files.

You can do memory mapping with StringViews.jl. Given a `StringView` of the memory mapped file, you can then call functions like `contains` or `match` and it will then load only the file pages that are needed. (Of course, if the string _isn’t_ found, these functions will still traverse the whole file, but if the file is larger than what fits in memory the VM should page things out when they are no longer needed.)

> [@lmiq](#):
>
> my goal is to get that version number

For example:

```julia
using StringViews, Mmap
open(filename, "r") do io
    s = StringView(mmap(io))
    v = match(r"\"Version\":\"([^\"]*)\"", s)
    return isnothing(v) ? v"0.0.0" : VersionNumber(v[1])
end

```

> [@lmiq](#):
>
> So now I’ve put the relevant field as the first field in the line […] and I’m reading char-by-char

If you know it’s the first field, and you can bound the length of the version, you could also just read the first few bytes of the file, e.g. with:

```julia
s = open(io -> String(readbytes!(io, UInt8[], 256)), filename, "r")

```

and then do regex extraction on that. This should be more efficient than reading character by character.

> [@lmiq](#):
>
> `str = str*c`

(Building a string this way is especially inefficient because it allocates a new string for each character, which is O(n^2) for n characters. If you are going to iteratively build strings in Julia, do it by writing into an `IOBuffer`.)

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [November 30, 2023, 7:35pm UTC](https://discourse.julialang.org/t/something-like-grep-q-string-filename-in-julia/106959/5 "2023-11-30T19:35:37Z")

</div>

Or use `readuntil`:

```julia
julia> readuntil(IOBuffer("""{"Version":"1.3.5-DEV","nbins":500"""), ',')

"{\"Version\":\"1.3.5-DEV\""

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [November 30, 2023, 7:38pm UTC](https://discourse.julialang.org/t/something-like-grep-q-string-filename-in-julia/106959/6 "2023-11-30T19:38:27Z")

</div>

> [@stillyslalom](#):
>
> Or use `readuntil`:

I was going to suggest that, but then I saw that @lmiq wanted to give up after 100 characters if a comma isn’t found, which `readuntil` doesn’t support. Depends on how badly you want to avoid reading in the whole file in the worst case of a comma-free file.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 30, 2023, 10:15pm UTC](https://discourse.julialang.org/t/something-like-grep-q-string-filename-in-julia/106959/7 "2023-11-30T22:15:29Z")

</div>

Thanks all, I think I’ll adapt my code to use `readuntil`.
