lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great Dirk Laurie once stated:
> 2013/12/28 Philipp Janda <siffiejoe@gmx.net>:
> 
> > But you can find out (in Lua 5.2) by calling the `close` method on the
> > returned file pointer:
> >
> >     > print( io.popen( "no_such_program" ):close() )
> >     sh: 1: no_such_program: not found
> >     nil     exit    127
> >     > print( io.popen( "false" ):close() )
> >     nil     exit    1
> >     > print( io.popen( "true" ):close() )
> >     true    exit    0
> 
> So one could use this instead of io.popen?
> 
> function popen(prog,mode)
> local cond,msg,code = io.popen(prog,mode):close()
> if code==127 then error("'"..prog.."' not found") end
> return io.popen(prog,mode)
> end

  No, much better to check for the existance of the program first:

function popen(program,mode)
  local function exists(name)
    local function check(file)
      local f = io.open(file,"r")
      if f ~= nil then
        f:close()
        return true
      else
        return false
      end
    end

    -- -------------------------------------------------------------------
    -- if given a relative or absolute path, just check the name.  No need
    -- to adapt this code for Windows---it'll work as is, as Windows will
    -- also support '/' for directory separators, and it also supports '.'
    -- for the current directory.
    -- -------------------------------------------------------------------

    if name:match("^%./") or name:match("^/") then
      return check(name)
    end

    -- -------------------------------------------------------------------
    -- now check the PATH.  If PATH isn't defined, just use an empty string
    -- to avoid some messy logic otherwise.
    -- -------------------------------------------------------------------

    local path = os.getenv("PATH") or ""

    for segment in path:gmatch("([^:]+):?") do
      local file = segment .. "/" .. name
      if check(file) then
        return true
      end
    end

    return false
  end

  local file = program:match("^(%S+)")
  if not exists(file) then
    error('"' .. program .. '" not found')
  end

  return io.popen(program,mode)
end

  But this fails to check if the resulting file is executable (although, if
it's in the PATH, it probably is), and program names with embedded spaces
are problematic.  Perhaps if you gave popen() three parameters, the first
being the program, the second being the rest of the command line, and the
final one being the mode would work around the space problem ... 

  -spc (It's always the little details ... )