I am developing a limited version of shell for my self. Here is a C++ program
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <unistd.h> using namespace std; const int MAX = 256; const int CMD_MAX = 10; char *valid_cmds = " ls ps df "; int main() { char line_input[MAX], the_cmd[CMD_MAX]; char *new_args[CMD_MAX], *cp; int i; while (1) { cout << "cmd> "; if (cin.getline(line_input, MAX, 'n') != NULL) { cp = line_input; i = 0; if ((new_args[i] = strtok(cp, " ")) != NULL) { strcpy(the_cmd, new_args[i]); strcat(the_cmd, " "); if ((strstr(valid_cmds, the_cmd) -valid_cmds)% 4 == 1) { do { cp = NULL; new_args[++i] = strtok(cp, " "); } while (i < CMD_MAX && new_args[i] != NULL); new_args[i] = NULL; switch (fork()) { case 0: execvp(new_args[0], new_args); perror("exec failure"); exit(1); case -1: perror("fork failure"); exit(2); default: // In the parent we should be waiting for // the child to finis h ; } } else cout << "huh?" << endl; } } } }
What I am not able to understand is when I compile this program I am getting error in line
(cin.getline(line_input, MAX, 'n') != NULL)
and the error is following I do a $ g++ p3.7.cpp
p3.7.cpp:10:20: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings] char *valid_cmds = " ls ps df "; ^~~~~~~~~~~~ p3.7.cpp: In function ‘int main()’: p3.7.cpp:18:42: error: no match for ‘operator!=’ (operand types are ‘std::basic_istream<char>’ and ‘long int’) if (cin.getline(line_input, MAX, 'n') != NULL) { ^ p3.7.cpp:18:42: note: candidate: operator!=(int, long int) <built-in> p3.7.cpp:18:42: note: no known conversion for argument 1 from ‘std::basic_istream<char>’ to ‘int’ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iosfwd:40:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/postypes.h:221:5: note: candidate: template<class _StateT> bool std::operator!=(const std::fpos<_StateT>&, const std::fpos<_StateT>&) operator!=(const fpos<_StateT>& __lhs, const fpos<_StateT>& __rhs) ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/postypes.h:221:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::fpos<_StateT>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_algobase.h:64:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/char_traits.h:39, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_pair.h:456:5: note: candidate: template<class _T1, class _T2> constexpr bool std::operator!=(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&) operator!=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_pair.h:456:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::pair<_T1, _T2>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_algobase.h:67:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/char_traits.h:39, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_iterator.h:311:5: note: candidate: template<class _Iterator> bool std::operator!=(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&) operator!=(const reverse_iterator<_Iterator>& __x, ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_iterator.h:311:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::reverse_iterator<_Iterator>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_algobase.h:67:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/char_traits.h:39, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_iterator.h:349:5: note: candidate: template<class _IteratorL, class _IteratorR> bool std::operator!=(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_IteratorR>&) operator!=(const reverse_iterator<_IteratorL>& __x, ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_iterator.h:349:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::reverse_iterator<_Iterator>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_algobase.h:67:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/char_traits.h:39, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_iterator.h:1130:5: note: candidate: template<class _IteratorL, class _IteratorR> bool std::operator!=(const std::move_iterator<_IteratorL>&, const std::move_iterator<_IteratorR>&) operator!=(const move_iterator<_IteratorL>& __x, ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_iterator.h:1130:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::move_iterator<_IteratorL>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_algobase.h:67:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/char_traits.h:39, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_iterator.h:1136:5: note: candidate: template<class _Iterator> bool std::operator!=(const std::move_iterator<_IteratorL>&, const std::move_iterator<_IteratorL>&) operator!=(const move_iterator<_Iterator>& __x, ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/stl_iterator.h:1136:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::move_iterator<_IteratorL>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/string:41:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/locale_classes.h:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/ios_base.h:41, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:42, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/allocator.h:158:5: note: candidate: template<class _T1, class _T2> bool std::operator!=(const std::allocator<_CharT>&, const std::allocator<_T2>&) operator!=(const allocator<_T1>&, const allocator<_T2>&) ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/allocator.h:158:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::allocator<_CharT>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/string:41:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/locale_classes.h:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/ios_base.h:41, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:42, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/allocator.h:164:5: note: candidate: template<class _Tp> bool std::operator!=(const std::allocator<_CharT>&, const std::allocator<_CharT>&) operator!=(const allocator<_Tp>&, const allocator<_Tp>&) ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/allocator.h:164:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::allocator<_CharT>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/string:52:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/locale_classes.h:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/ios_base.h:41, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:42, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/basic_string.h:6044:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> bool std::operator!=(const std::basic_string<_CharT, _Traits, _Alloc>&, const std::basic_string<_CharT, _Traits, _Alloc>&) operator!=(const basic_string<_CharT, _Traits, _Alloc>& __lhs, ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/basic_string.h:6044:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::basic_string<_CharT, _Traits, _Alloc>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/string:52:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/locale_classes.h:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/ios_base.h:41, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:42, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/basic_string.h:6057:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> bool std::operator!=(const _CharT*, const std::basic_string<_CharT, _Traits, _Alloc>&) operator!=(const _CharT* __lhs, ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/basic_string.h:6057:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: mismatched types ‘const _CharT*’ and ‘std::basic_istream<char>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/string:52:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/locale_classes.h:40, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/ios_base.h:41, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:42, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/basic_string.h:6069:5: note: candidate: template<class _CharT, class _Traits, class _Alloc> bool std::operator!=(const std::basic_string<_CharT, _Traits, _Alloc>&, const _CharT*) operator!=(const basic_string<_CharT, _Traits, _Alloc>& __lhs, ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/basic_string.h:6069:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::basic_string<_CharT, _Traits, _Alloc>’ if (cin.getline(line_input, MAX, 'n') != NULL) { ^ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/ios_base.h:46:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:42, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/system_error:319:3: note: candidate: bool std::operator!=(const std::error_code&, const std::error_code&) operator!=(const error_code& __lhs, const error_code& __rhs) noexcept ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/system_error:319:3: note: no known conversion for argument 1 from ‘std::basic_istream<char>’ to ‘const std::error_code&’ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/system_error:323:3: note: candidate: bool std::operator!=(const std::error_code&, const std::error_condition&) operator!=(const error_code& __lhs, const error_condition& __rhs) noexcept ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/system_error:323:3: note: no known conversion for argument 1 from ‘std::basic_istream<char>’ to ‘const std::error_code&’ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/system_error:327:3: note: candidate: bool std::operator!=(const std::error_condition&, const std::error_code&) operator!=(const error_condition& __lhs, const error_code& __rhs) noexcept ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/system_error:327:3: note: no known conversion for argument 1 from ‘std::basic_istream<char>’ to ‘const std::error_condition&’ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/system_error:331:3: note: candidate: bool std::operator!=(const std::error_condition&, const std::error_condition&) operator!=(const error_condition& __lhs, ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/system_error:331:3: note: no known conversion for argument 1 from ‘std::basic_istream<char>’ to ‘const std::error_condition&’ In file included from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/locale_facets.h:48:0, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/basic_ios.h:37, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ios:44, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/ostream:38, from /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/iostream:39, from p3.7.cpp:2: /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/streambuf_iterator.h:210:5: note: candidate: template<class _CharT, class _Traits> bool std::operator!=(const std::istreambuf_iterator<_CharT, _Traits>&, const std::istreambuf_iterator<_CharT, _Traits>&) operator!=(const istreambuf_iterator<_CharT, _Traits>& __a, ^~~~~~~~ /usr/lib/gcc/x86_64-pc-cygwin/7.3.0/include/c++/bits/streambuf_iterator.h:210:5: note: template argument deduction/substitution failed: In file included from /usr/include/sys/unistd.h:14:0, from /usr/include/unistd.h:4, from p3.7.cpp:6: p3.7.cpp:18:45: note: ‘std::basic_istream<char>’ is not derived from ‘const std::istreambuf_iterator<_CharT, _Traits>’ if (cin.getline(line_input, MAX, 'n') != NULL) {
What is the mistake above I am doing. Do I need to include some header file which I have forgotten.
Advertisement
Answer
More of a style comment than anything. I’d be inclined to break up your main function into separate functions, each dealing with a different concern of the problem.
In this example I’ve used c++ data constructs rather than c-style ones.
I’ve also used boost::optional
and boost::tokenizer
.
The boost library suite is invaluable to any c++ developer as it provides many of the essential application programming tools that the c++ standard library fails to provide.
#include <boost/optional.hpp> #include <boost/tokenizer.hpp> #include <boost/algorithm/string.hpp> #include <iostream> #include <unistd.h> #include <sys/wait.h> using boost::optional; using std::string; using std::vector; void prompt(std::istream& is) { if (std::addressof(is) == std::addressof(std::cin)) { std::cout << "cmd> "; } } optional<string> next_line(std::istream& is) { auto result = optional<string>(); std::string line; while (1) { prompt(is); if (!getline(is, line)) break; if (!line.empty()) { result = line; break; } } return result; } vector<string> tokenise(std::string const& source) { using char_function = boost::char_separator<char>; auto tokens = boost::tokenizer<char_function>(source, char_function(" ")); return vector<string>(tokens.begin(), tokens.end()); } auto to_char_data_vector(vector<string>::iterator first, vector<string>::iterator last) -> vector<char *> { auto to_char_data = [](std::string& str) { return str.data(); }; auto result = vector<char *>(); std::transform(first, last, back_inserter(result), to_char_data); return result; }; auto append_null(vector<char*> v) -> vector<char *> { v.push_back(nullptr); return v; } int sub_command(string const& cmd, vector<string>& args) // note - not const. { auto do_error = [](const char *message) { auto retcode = errno; std::cerr << message << std::endl; return retcode; }; auto pid = fork(); if (pid == -1) { return do_error("fork failure"); } else if (pid == 0) { auto result = execv(cmd.data(), append_null(to_char_data_vector(begin(args), std::end(args))) .data()); std::exit(do_error("execv failure")); } else { int stat = 0; auto waitresult = waitpid(pid, &stat, 0); if (waitresult == -1) return do_error("failed to wait"); return WEXITSTATUS(stat); } } /// @pre tokens.length() >= 1 int interpret(vector<string> const& tokens) { auto args = vector<string>(next(begin(tokens)), std::end(tokens)); auto& cmd = tokens[0]; if (boost::iequals(cmd, "exit")) { std::exit(args.empty() ? 0 : std::stoi(args[0])); } else { return sub_command(cmd, args); } } int main() { while (auto opt_line = next_line(std::cin)) { auto tokens = tokenise(*opt_line); if (tokens.empty()) continue; auto return_code = interpret(tokens); std::cout << "command returned: " << return_code << std::endl; } }
example run:
cmd> /bin/ls . CMakeCache.txt TryThings.cbp trythings CMakeFiles _3rdParty Makefile cmake_install.cmake command returned: 0 cmd> exit 20 Process finished with exit code 20
Note that I had to specify the exact path of the ls
command. evecv
knows nothing about search paths.