mirror of https://github.com/tstack/lnav.git
[cmds] add :redirect-to command for redirecting the output of commands in scripts
Related to #551
This commit is contained in:
parent
ea5ac46c0e
commit
ac7ae1275a
4
NEWS
4
NEWS
|
@ -3,6 +3,10 @@ lnav v0.8.5:
|
||||||
Features:
|
Features:
|
||||||
* The ":write-*" commands will now accept "/dev/clipboard" as a file name
|
* The ":write-*" commands will now accept "/dev/clipboard" as a file name
|
||||||
that writes to the system clipboard.
|
that writes to the system clipboard.
|
||||||
|
* Added a ":redirect-to <path>" command to redirect command output to the
|
||||||
|
given file. This command is mostly useful in scripts where one might
|
||||||
|
want to redirect all output from commands like ":echo" and ":write-to -"
|
||||||
|
to a single file.
|
||||||
|
|
||||||
Interface Changes:
|
Interface Changes:
|
||||||
* The auto-complete behavior in the prompt has been modified to fall back
|
* The auto-complete behavior in the prompt has been modified to fall back
|
||||||
|
|
|
@ -143,6 +143,10 @@ Output
|
||||||
shell command and open the output in lnav.
|
shell command and open the output in lnav.
|
||||||
* pipe-line-to <shell-cmd> - Pipe the top line in the current view to a shell
|
* pipe-line-to <shell-cmd> - Pipe the top line in the current view to a shell
|
||||||
command and open the output in lnav.
|
command and open the output in lnav.
|
||||||
|
* redirect-to [path] - If a path is given, all output from commands, like
|
||||||
|
":echo" and when writing to stdout (e.g. :write-to -), will be sent to the
|
||||||
|
given file. If no path is specified, the current redirect will be cleared
|
||||||
|
and output will be captured as it was before the redirect was done.
|
||||||
|
|
||||||
.. _misc-cmd:
|
.. _misc-cmd:
|
||||||
|
|
||||||
|
|
|
@ -385,6 +385,7 @@ static string execute_file_contents(exec_context &ec, const string &path, bool m
|
||||||
pair<string, string> dir_and_base = split_path(path);
|
pair<string, string> dir_and_base = split_path(path);
|
||||||
|
|
||||||
ec.ec_path_stack.push_back(dir_and_base.first);
|
ec.ec_path_stack.push_back(dir_and_base.first);
|
||||||
|
ec.ec_output_stack.emplace_back(nonstd::nullopt);
|
||||||
while ((line_size = getline(&line, &line_max_size, file)) != -1) {
|
while ((line_size = getline(&line, &line_max_size, file)) != -1) {
|
||||||
line_number += 1;
|
line_number += 1;
|
||||||
|
|
||||||
|
@ -431,6 +432,7 @@ static string execute_file_contents(exec_context &ec, const string &path, bool m
|
||||||
} else {
|
} else {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
ec.ec_output_stack.pop_back();
|
||||||
ec.ec_path_stack.pop_back();
|
ec.ec_path_stack.pop_back();
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -731,7 +733,26 @@ int sql_callback(exec_context &ec, sqlite3_stmt *stmt)
|
||||||
|
|
||||||
future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &fd)
|
future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &fd)
|
||||||
{
|
{
|
||||||
if (lnav_data.ld_output_stack.empty()) {
|
auto out = ec.get_output();
|
||||||
|
|
||||||
|
if (out) {
|
||||||
|
FILE *file = *out;
|
||||||
|
|
||||||
|
return std::async(std::launch::async, [&fd, file]() {
|
||||||
|
char buffer[1024];
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
if (file == stdout) {
|
||||||
|
lnav_data.ld_stdout_used = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
|
||||||
|
fwrite(buffer, rc, 1, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
auto pp = make_shared<piper_proc>(fd, false);
|
auto pp = make_shared<piper_proc>(fd, false);
|
||||||
static int exec_count = 0;
|
static int exec_count = 0;
|
||||||
char desc[128];
|
char desc[128];
|
||||||
|
@ -755,22 +776,6 @@ future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &f
|
||||||
task();
|
task();
|
||||||
|
|
||||||
return task.get_future();
|
return task.get_future();
|
||||||
} else {
|
|
||||||
return std::async(std::launch::async, [&]() {
|
|
||||||
FILE *file = lnav_data.ld_output_stack.top();
|
|
||||||
char buffer[1024];
|
|
||||||
ssize_t rc;
|
|
||||||
|
|
||||||
if (file == stdout) {
|
|
||||||
lnav_data.ld_stdout_used = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
|
|
||||||
fwrite(buffer, rc, 1, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return string();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "optional.hpp"
|
||||||
#include "auto_fd.hh"
|
#include "auto_fd.hh"
|
||||||
#include "attr_line.hh"
|
#include "attr_line.hh"
|
||||||
#include "textview_curses.hh"
|
#include "textview_curses.hh"
|
||||||
|
@ -47,9 +48,9 @@ typedef std::future<std::string> (*pipe_callback_t)(
|
||||||
exec_context &ec, const std::string &cmdline, auto_fd &fd);
|
exec_context &ec, const std::string &cmdline, auto_fd &fd);
|
||||||
|
|
||||||
struct exec_context {
|
struct exec_context {
|
||||||
exec_context(std::vector<logline_value> *line_values = NULL,
|
exec_context(std::vector<logline_value> *line_values = nullptr,
|
||||||
sql_callback_t sql_callback = NULL,
|
sql_callback_t sql_callback = nullptr,
|
||||||
pipe_callback_t pipe_callback = NULL)
|
pipe_callback_t pipe_callback = nullptr)
|
||||||
: ec_top_line(vis_line_t(0)),
|
: ec_top_line(vis_line_t(0)),
|
||||||
ec_dry_run(false),
|
ec_dry_run(false),
|
||||||
ec_line_values(line_values),
|
ec_line_values(line_values),
|
||||||
|
@ -58,6 +59,7 @@ struct exec_context {
|
||||||
this->ec_local_vars.push(std::map<std::string, std::string>());
|
this->ec_local_vars.push(std::map<std::string, std::string>());
|
||||||
this->ec_path_stack.emplace_back(".");
|
this->ec_path_stack.emplace_back(".");
|
||||||
this->ec_source.emplace("unknown", 0);
|
this->ec_source.emplace("unknown", 0);
|
||||||
|
this->ec_output_stack.emplace_back(nonstd::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_error_prefix() {
|
std::string get_error_prefix() {
|
||||||
|
@ -70,6 +72,18 @@ struct exec_context {
|
||||||
return "error:" + source.first + ":" + std::to_string(source.second) + ":";
|
return "error:" + source.first + ":" + std::to_string(source.second) + ":";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nonstd::optional<FILE *> get_output() {
|
||||||
|
for (auto iter = this->ec_output_stack.rbegin();
|
||||||
|
iter != this->ec_output_stack.rend();
|
||||||
|
++iter) {
|
||||||
|
if (*iter) {
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nonstd::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
vis_line_t ec_top_line;
|
vis_line_t ec_top_line;
|
||||||
bool ec_dry_run;
|
bool ec_dry_run;
|
||||||
|
|
||||||
|
@ -79,6 +93,7 @@ struct exec_context {
|
||||||
std::map<std::string, std::string> ec_global_vars;
|
std::map<std::string, std::string> ec_global_vars;
|
||||||
std::vector<std::string> ec_path_stack;
|
std::vector<std::string> ec_path_stack;
|
||||||
std::stack<std::pair<std::string, int>> ec_source;
|
std::stack<std::pair<std::string, int>> ec_source;
|
||||||
|
std::vector<nonstd::optional<FILE *>> ec_output_stack;
|
||||||
|
|
||||||
attr_line_t ec_accumulator;
|
attr_line_t ec_accumulator;
|
||||||
|
|
||||||
|
|
20
src/lnav.cc
20
src/lnav.cc
|
@ -3302,10 +3302,8 @@ int main(int argc, char *argv[])
|
||||||
lnav_data.ld_vtab_manager->register_vtab(new log_format_vtab_impl(
|
lnav_data.ld_vtab_manager->register_vtab(new log_format_vtab_impl(
|
||||||
*log_format::find_root_format("generic_log")));
|
*log_format::find_root_format("generic_log")));
|
||||||
|
|
||||||
for (std::vector<log_format *>::iterator iter = log_format::get_root_formats().begin();
|
for (auto &iter : log_format::get_root_formats()) {
|
||||||
iter != log_format::get_root_formats().end();
|
log_vtab_impl *lvi = iter->get_vtab_impl();
|
||||||
++iter) {
|
|
||||||
log_vtab_impl *lvi = (*iter)->get_vtab_impl();
|
|
||||||
|
|
||||||
if (lvi != NULL) {
|
if (lvi != NULL) {
|
||||||
lnav_data.ld_vtab_manager->register_vtab(lvi);
|
lnav_data.ld_vtab_manager->register_vtab(lvi);
|
||||||
|
@ -3481,10 +3479,8 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
if (lnav_data.ld_flags & LNF_CHECK_CONFIG) {
|
if (lnav_data.ld_flags & LNF_CHECK_CONFIG) {
|
||||||
rescan_files(true);
|
rescan_files(true);
|
||||||
for (auto file_iter = lnav_data.ld_files.begin();
|
for (auto &ld_file : lnav_data.ld_files) {
|
||||||
file_iter != lnav_data.ld_files.end();
|
auto lf = ld_file;
|
||||||
++file_iter) {
|
|
||||||
auto lf = (*file_iter);
|
|
||||||
|
|
||||||
lf->rebuild_index();
|
lf->rebuild_index();
|
||||||
|
|
||||||
|
@ -3496,7 +3492,7 @@ int main(int argc, char *argv[])
|
||||||
retval = EXIT_FAILURE;
|
retval = EXIT_FAILURE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (logfile::iterator line_iter = lf->begin();
|
for (auto line_iter = lf->begin();
|
||||||
line_iter != lf->end();
|
line_iter != lf->end();
|
||||||
++line_iter) {
|
++line_iter) {
|
||||||
if (!line_iter->is_continued()) {
|
if (!line_iter->is_continued()) {
|
||||||
|
@ -3587,14 +3583,14 @@ int main(int argc, char *argv[])
|
||||||
log_info("lnav_data:");
|
log_info("lnav_data:");
|
||||||
log_info(" flags=%x", lnav_data.ld_flags);
|
log_info(" flags=%x", lnav_data.ld_flags);
|
||||||
log_info(" commands:");
|
log_info(" commands:");
|
||||||
for (std::list<string>::iterator cmd_iter =
|
for (auto cmd_iter =
|
||||||
lnav_data.ld_commands.begin();
|
lnav_data.ld_commands.begin();
|
||||||
cmd_iter != lnav_data.ld_commands.end();
|
cmd_iter != lnav_data.ld_commands.end();
|
||||||
++cmd_iter) {
|
++cmd_iter) {
|
||||||
log_info(" %s", cmd_iter->c_str());
|
log_info(" %s", cmd_iter->c_str());
|
||||||
}
|
}
|
||||||
log_info(" files:");
|
log_info(" files:");
|
||||||
for (map<string, logfile_open_options>::iterator file_iter =
|
for (auto file_iter =
|
||||||
lnav_data.ld_file_names.begin();
|
lnav_data.ld_file_names.begin();
|
||||||
file_iter != lnav_data.ld_file_names.end();
|
file_iter != lnav_data.ld_file_names.end();
|
||||||
++file_iter) {
|
++file_iter) {
|
||||||
|
@ -3608,7 +3604,7 @@ int main(int argc, char *argv[])
|
||||||
bool found_error = false;
|
bool found_error = false;
|
||||||
|
|
||||||
init_session();
|
init_session();
|
||||||
lnav_data.ld_output_stack.push(stdout);
|
lnav_data.ld_exec_context.ec_output_stack.back() = stdout;
|
||||||
alerter::singleton().enabled(false);
|
alerter::singleton().enabled(false);
|
||||||
|
|
||||||
log_tc = &lnav_data.ld_views[LNV_LOG];
|
log_tc = &lnav_data.ld_views[LNV_LOG];
|
||||||
|
|
|
@ -305,8 +305,6 @@ struct _lnav_data {
|
||||||
|
|
||||||
relative_time ld_last_relative_time;
|
relative_time ld_last_relative_time;
|
||||||
|
|
||||||
std::stack<FILE *> ld_output_stack;
|
|
||||||
|
|
||||||
std::map<std::string, std::vector<script_metadata> > ld_scripts;
|
std::map<std::string, std::vector<script_metadata> > ld_scripts;
|
||||||
|
|
||||||
exec_context ld_exec_context;
|
exec_context ld_exec_context;
|
||||||
|
|
|
@ -568,7 +568,9 @@ static string com_save_to(exec_context &ec, string cmdline, vector<string> &args
|
||||||
toclose = outfile;
|
toclose = outfile;
|
||||||
}
|
}
|
||||||
else if (split_args[0] == "-" || split_args[0] == "/dev/stdout") {
|
else if (split_args[0] == "-" || split_args[0] == "/dev/stdout") {
|
||||||
if (lnav_data.ld_output_stack.empty()) {
|
auto ec_out = ec.get_output();
|
||||||
|
|
||||||
|
if (!ec_out) {
|
||||||
outfile = stdout;
|
outfile = stdout;
|
||||||
nodelay(lnav_data.ld_window, 0);
|
nodelay(lnav_data.ld_window, 0);
|
||||||
endwin();
|
endwin();
|
||||||
|
@ -583,7 +585,7 @@ static string com_save_to(exec_context &ec, string cmdline, vector<string> &args
|
||||||
"----------------\n\n");
|
"----------------\n\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
outfile = lnav_data.ld_output_stack.top();
|
outfile = *ec_out;
|
||||||
}
|
}
|
||||||
if (outfile == stdout) {
|
if (outfile == stdout) {
|
||||||
lnav_data.ld_stdout_used = true;
|
lnav_data.ld_stdout_used = true;
|
||||||
|
@ -673,7 +675,7 @@ static string com_save_to(exec_context &ec, string cmdline, vector<string> &args
|
||||||
|
|
||||||
if ((handle = yajl_gen_alloc(NULL)) == NULL) {
|
if ((handle = yajl_gen_alloc(NULL)) == NULL) {
|
||||||
if (outfile != stdout) {
|
if (outfile != stdout) {
|
||||||
fclose(outfile);
|
closer(outfile);
|
||||||
}
|
}
|
||||||
return "error: unable to allocate memory";
|
return "error: unable to allocate memory";
|
||||||
}
|
}
|
||||||
|
@ -945,6 +947,52 @@ static string com_pipe_to(exec_context &ec, string cmdline, vector<string> &args
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string com_redirect_to(exec_context &ec, string cmdline, vector<string> &args)
|
||||||
|
{
|
||||||
|
if (args.empty()) {
|
||||||
|
args.emplace_back("filename");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.size() == 1) {
|
||||||
|
if (ec.ec_dry_run) {
|
||||||
|
return "info: redirect will be cleared";
|
||||||
|
}
|
||||||
|
|
||||||
|
ec.ec_output_stack.back() = nonstd::nullopt;
|
||||||
|
return "info: cleared redirect";
|
||||||
|
}
|
||||||
|
|
||||||
|
string fn = trim(remaining_args(cmdline, args));
|
||||||
|
vector<string> split_args;
|
||||||
|
shlex lexer(fn);
|
||||||
|
scoped_resolver scopes = {
|
||||||
|
&ec.ec_local_vars.top(),
|
||||||
|
&ec.ec_global_vars,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!lexer.split(split_args, scopes)) {
|
||||||
|
return "error: unable to parse arguments";
|
||||||
|
}
|
||||||
|
if (split_args.size() > 1) {
|
||||||
|
return "error: more than one file name was matched";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ec.ec_dry_run) {
|
||||||
|
return "info: output will be redirected to -- " + split_args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *file = fopen(split_args[0].c_str(), "w");
|
||||||
|
|
||||||
|
if (file == nullptr) {
|
||||||
|
return "error: unable to open file -- " + split_args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
ec.ec_output_stack.back() = file;
|
||||||
|
|
||||||
|
return "info: redirecting output to file -- " + split_args[0];
|
||||||
|
}
|
||||||
|
|
||||||
static string com_highlight(exec_context &ec, string cmdline, vector<string> &args)
|
static string com_highlight(exec_context &ec, string cmdline, vector<string> &args)
|
||||||
{
|
{
|
||||||
string retval = "error: expecting regular expression to highlight";
|
string retval = "error: expecting regular expression to highlight";
|
||||||
|
@ -2933,14 +2981,15 @@ static string com_echo(exec_context &ec, string cmdline, vector<string> &args)
|
||||||
retval = "";
|
retval = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ec_out = ec.get_output();
|
||||||
if (ec.ec_dry_run) {
|
if (ec.ec_dry_run) {
|
||||||
lnav_data.ld_preview_status_source.get_description()
|
lnav_data.ld_preview_status_source.get_description()
|
||||||
.set_value("The text to output:");
|
.set_value("The text to output:");
|
||||||
lnav_data.ld_preview_source.replace_with(attr_line_t(retval));
|
lnav_data.ld_preview_source.replace_with(attr_line_t(retval));
|
||||||
retval = "";
|
retval = "";
|
||||||
}
|
}
|
||||||
else if (!lnav_data.ld_output_stack.empty()) {
|
else if (ec_out) {
|
||||||
FILE *outfile = lnav_data.ld_output_stack.top();
|
FILE *outfile = *ec_out;
|
||||||
|
|
||||||
if (outfile == stdout) {
|
if (outfile == stdout) {
|
||||||
lnav_data.ld_stdout_used = true;
|
lnav_data.ld_stdout_used = true;
|
||||||
|
@ -2951,6 +3000,8 @@ static string com_echo(exec_context &ec, string cmdline, vector<string> &args)
|
||||||
putc('\n', outfile);
|
putc('\n', outfile);
|
||||||
}
|
}
|
||||||
fflush(outfile);
|
fflush(outfile);
|
||||||
|
|
||||||
|
retval = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3838,6 +3889,19 @@ readline_context::command_t STD_COMMANDS[] = {
|
||||||
.with_tags({"io"})
|
.with_tags({"io"})
|
||||||
.with_example({"sed -e 's/foo/bar/g'"})
|
.with_example({"sed -e 's/foo/bar/g'"})
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"redirect-to",
|
||||||
|
com_redirect_to,
|
||||||
|
|
||||||
|
help_text(":redirect-to")
|
||||||
|
.with_summary("Redirect the output of commands to the given file")
|
||||||
|
.with_parameter(help_text(
|
||||||
|
"path", "The path to the file to write."
|
||||||
|
" If not specified, the current redirect will be cleared")
|
||||||
|
.optional())
|
||||||
|
.with_tags({"io", "scripting"})
|
||||||
|
.with_example({"/tmp/script-output.txt"})
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"enable-filter",
|
"enable-filter",
|
||||||
com_enable_filter,
|
com_enable_filter,
|
||||||
|
|
|
@ -484,14 +484,14 @@ void rl_callback(void *dummy, readline_curses *rc)
|
||||||
time_t current_time = time(NULL);
|
time_t current_time = time(NULL);
|
||||||
string path_and_args = rc->get_value();
|
string path_and_args = rc->get_value();
|
||||||
|
|
||||||
lnav_data.ld_output_stack.push(tmpout);
|
ec.ec_output_stack.back() = tmpout.in();
|
||||||
string result = execute_file(ec, path_and_args);
|
string result = execute_file(ec, path_and_args);
|
||||||
string::size_type lf_index = result.find('\n');
|
string::size_type lf_index = result.find('\n');
|
||||||
if (lf_index != string::npos) {
|
if (lf_index != string::npos) {
|
||||||
result = result.substr(0, lf_index);
|
result = result.substr(0, lf_index);
|
||||||
}
|
}
|
||||||
rc->set_value(result);
|
rc->set_value(result);
|
||||||
lnav_data.ld_output_stack.pop();
|
ec.ec_output_stack.back() = nonstd::nullopt;
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
@ -506,7 +506,7 @@ void rl_callback(void *dummy, readline_curses *rc)
|
||||||
lnav_data.ld_file_names[desc]
|
lnav_data.ld_file_names[desc]
|
||||||
.with_fd(fd_copy)
|
.with_fd(fd_copy)
|
||||||
.with_detect_format(false);
|
.with_detect_format(false);
|
||||||
lnav_data.ld_files_to_front.push_back(make_pair(desc, 0));
|
lnav_data.ld_files_to_front.emplace_back(desc, 0);
|
||||||
|
|
||||||
if (lnav_data.ld_rl_view != NULL) {
|
if (lnav_data.ld_rl_view != NULL) {
|
||||||
lnav_data.ld_rl_view->set_alt_value(
|
lnav_data.ld_rl_view->set_alt_value(
|
||||||
|
|
|
@ -348,6 +348,8 @@ dist_noinst_DATA = \
|
||||||
formats/jsontest3/format.json \
|
formats/jsontest3/format.json \
|
||||||
formats/nestedjson/format.json \
|
formats/nestedjson/format.json \
|
||||||
formats/scripts/multiline-echo.lnav \
|
formats/scripts/multiline-echo.lnav \
|
||||||
|
formats/scripts/redirecting.lnav \
|
||||||
|
formats/scripts/nested-redirecting.lnav \
|
||||||
formats/sqldir/init.sql \
|
formats/sqldir/init.sql \
|
||||||
formats/timestamp/format.json \
|
formats/timestamp/format.json \
|
||||||
log-samples/sample-27353a72ba4025448f261dcfa6ea16e474187795.txt \
|
log-samples/sample-27353a72ba4025448f261dcfa6ea16e474187795.txt \
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
:echo HOWDY!
|
||||||
|
:redirect-to hw2.txt
|
||||||
|
:echo HELLO, WORLD!
|
||||||
|
:redirect-to
|
||||||
|
:echo GOODBYE, WORLD!
|
|
@ -0,0 +1,6 @@
|
||||||
|
:echo Howdy!
|
||||||
|
:redirect-to hw.txt
|
||||||
|
:echo Hello, World!
|
||||||
|
|nested-redirecting
|
||||||
|
:redirect-to
|
||||||
|
:echo Goodbye, World!
|
|
@ -16,3 +16,36 @@ check_output "multiline-echo is not working?" <<EOF
|
||||||
Hello, World!
|
Hello, World!
|
||||||
Goodbye, World!
|
Goodbye, World!
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
run_test ${lnav_test} -n -d /tmp/lnav.err \
|
||||||
|
-I ${test_dir} \
|
||||||
|
-f 'redirecting' \
|
||||||
|
scripts-empty
|
||||||
|
|
||||||
|
check_error_output "redirecting has errors?" <<EOF
|
||||||
|
EOF
|
||||||
|
|
||||||
|
check_output "redirecting is not working?" <<EOF
|
||||||
|
Howdy!
|
||||||
|
Goodbye, World!
|
||||||
|
EOF
|
||||||
|
|
||||||
|
diff -w -u - hw.txt <<EOF
|
||||||
|
Hello, World!
|
||||||
|
HOWDY!
|
||||||
|
GOODBYE, WORLD!
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if test $? -ne 0; then
|
||||||
|
echo "Script output was not redirected?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
diff -w -u - hw2.txt <<EOF
|
||||||
|
HELLO, WORLD!
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if test $? -ne 0; then
|
||||||
|
echo "Script output was not redirected?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
Loading…
Reference in New Issue