5

I want to search for existence of a file using child_process in node:

const { exec } = require('child_process');
exec('ls | grep "filename"', (err, result) => {...})

When the filename exists, exec result is fine. But when the filename doesn't exist, I get an error:

Command failed: ls | grep "filename"

In this case, how can I tell if it's an error executing the command, or just because no result is found?

EDIT

Thanks for the advice on not searching for a file this way. The above code is not the actual code, but just a demo piece illustrating my problem with grep. In my actual case I'm searching for keywords in the output by task spooler, thus I used exec and tsp -l | grep ...

Stanley Luo
  • 3,689
  • 5
  • 34
  • 64
  • BTW, this is an extremely poor way to tell if a file exists. It'll tell you that `file10` exists if `file101` is present, for example; is prone to all the bugs in http://mywiki.wooledge.org/ParsingLs, will ignore dotfiles, has unnecessarily large startup costs (invoking at least three separate UNIX processes), will require an exceptionally long time to run if reading through a 10,000-file directory... and if you try to check for a file named `foo$(rm -rf ~)bar`, you'll have a **very** bad day. – Charles Duffy Dec 13 '17 at 01:38
  • It should be noted, I am also not an advocate of exec ing shell command in higher-level programming languages, I am unfortunately not a node expert but if possible I would try to achieve this with node syntax first, then as a last resort leverage the power of the shell! – Travis Clarke Dec 13 '17 at 01:40
  • 2
    See [check synchronously if file/directory exists in node.js](https://stackoverflow.com/questions/4482686/check-synchronously-if-file-directory-exists-in-node-js) for a better-practice synchronous approach -- or https://github.com/ShMcK/node-file-exists for a non-deprecated async alternative. – Charles Duffy Dec 13 '17 at 01:41
  • 1
    The correct way to do this in shell, by the way, is `test -e filename` -- no `ls`, no `grep`. But even then, it introduces security risks to substitute an arbitrary/unknown filename into a string that the shell parses as code. – Charles Duffy Dec 13 '17 at 01:42
  • (argh -- I was incorrect to say "non-deprecated async alternative" -- that *is* a synchronous implementation as well. Still, correctly implemented, it's a single syscall, and not one that *has* a polling/async-based implementation at the filesystem level) – Charles Duffy Dec 13 '17 at 01:49
  • 1
    @CharlesDuffy – I agree with you regarding the preferred approach here. My answer stands as merely an explanation for how Node populates the error code value in the callback and how one can branch appropriately on this value. For better or worse, I made a note of this in the answer to discourage others from *preferring* the approach in my answer where *possible*. – Travis Clarke Dec 13 '17 at 01:49
  • 1
    Whether **sync** or **async**, I agree that a high-level Node API implementation, in any form, will include better accuracy and error handling than an `exec` call. – Travis Clarke Dec 13 '17 at 01:54

1 Answers1

9

You can determine this by looking at the value of err.code in the callback. It is documented in more detail in the Node.js docs.

Since the last command in the pipe is grep, consult the grep manpage for a complete list of status codes to branch your logic appropriately. In your case, grep will return a status code of 1 if no lines were selected (i.e. "there are no results"), so if err.code === 1, then you know no files were matched.

Note: as mentioned by @CharlesDuffy, It should be preferred to achieve your desired file manipulations via the Node.js File System API. Leverage this answer as an alternative for situations where exec is explicitly needed.

Travis Clarke
  • 5,951
  • 6
  • 29
  • 36