Skip to content

Commit f619a8a

Browse files
committed
script: support non-option argument as command
1 parent 49a7b29 commit f619a8a

File tree

2 files changed

+66
-7
lines changed

2 files changed

+66
-7
lines changed

term-utils/script.1.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ script - make typescript of terminal session
4747
4848
== SYNOPSIS
4949
50-
*script* [options] [_file_]
50+
*script* [options] [_file_] [ -- program [arguments]]
5151
5252
== DESCRIPTION
5353
@@ -67,7 +67,7 @@ Below, the _size_ argument may be followed by the multiplicative suffixes KiB (=
6767
Append the output to _file_ or to _typescript_, retaining the prior contents.
6868
6969
*-c*, *--command* _command_::
70-
Run the _command_ rather than an interactive shell. This makes it easy for a script to capture the output of a program that behaves differently when its stdout is not a tty.
70+
Run the _command_ rather than an interactive shell. This makes it easy for a script to capture the output of a program that behaves differently when its stdout is not a tty. you can also specify the command after '--'.
7171
7272
*-E*, *--echo* _when_::
7373
This option controls the *ECHO* flag for the slave end of the session's pseudoterminal. The supported modes are _always_, _never_, or _auto_.

term-utils/script.c

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ static void __attribute__((__noreturn__)) usage(void)
190190
{
191191
FILE *out = stdout;
192192
fputs(USAGE_HEADER, out);
193-
fprintf(out, _(" %s [options] [file]\n"), program_invocation_short_name);
193+
fprintf(out, _(" %s [options] [file] [ -- program [arguments]]\n"), program_invocation_short_name);
194194

195195
fputs(USAGE_SEPARATOR, out);
196196
fputs(_("Make a typescript of a terminal session.\n"), out);
@@ -207,7 +207,8 @@ static void __attribute__((__noreturn__)) usage(void)
207207
fputs(USAGE_SEPARATOR, out);
208208

209209
fputs(_(" -a, --append append to the log file\n"), out);
210-
fputs(_(" -c, --command <command> run command rather than interactive shell\n"), out);
210+
fputs(_(" -c, --command <command> run command rather than interactive shell\n"
211+
" you can also specify the command after '--'\n"), out);
211212
fputs(_(" -e, --return return exit code of the child process\n"), out);
212213
fputs(_(" -f, --flush run flush after each write\n"), out);
213214
fputs(_(" --force use output file even when it is a link\n"), out);
@@ -758,6 +759,31 @@ static void die_if_link(struct script_control *ctl, const char *filename)
758759
"Program not started."), filename);
759760
}
760761

762+
static char *concat_command(int argc, char *argv[])
763+
{
764+
int i;
765+
size_t len = 0;
766+
char *result, *p;
767+
768+
for (i = 0; i < argc; i++)
769+
len += strlen(argv[i]) + 1;
770+
771+
if (len == 0)
772+
return NULL;
773+
774+
p = result = xmalloc(len + 1);
775+
if (!result)
776+
return NULL;
777+
778+
for (i = 0; i < argc; i++) {
779+
memcpy(p, argv[i], strlen(argv[i]));
780+
p += strlen(argv[i]);
781+
*p++ = ' ';
782+
}
783+
*--p = '\0';
784+
return result;
785+
}
786+
761787
int main(int argc, char **argv)
762788
{
763789
struct script_control ctl = {
@@ -768,6 +794,7 @@ int main(int argc, char **argv)
768794
int ch, format = 0, caught_signal = 0, rc = 0, echo = 1;
769795
const char *outfile = NULL, *infile = NULL;
770796
const char *timingfile = NULL, *shell = NULL;
797+
char *posixly_correct;
771798

772799
enum { FORCE_OPTION = CHAR_MAX + 1 };
773800

@@ -813,6 +840,10 @@ int main(int argc, char **argv)
813840

814841
ctl.isterm = isatty(STDIN_FILENO);
815842

843+
/* assure the order of argv[] unchanged */
844+
posixly_correct = getenv("POSIXLY_CORRECT");
845+
setenv("POSIXLY_CORRECT", "1", 1);
846+
816847
while ((ch = getopt_long(argc, argv, "aB:c:eE:fI:O:o:qm:T:t::Vh", longopts, NULL)) != -1) {
817848

818849
err_exclusive_options(ch, longopts, excl, excl_st);
@@ -888,12 +919,20 @@ int main(int argc, char **argv)
888919
errtryhelp(EXIT_FAILURE);
889920
}
890921
}
922+
923+
/* restore POSIXLY_CORRECT */
924+
if (posixly_correct)
925+
setenv("POSIXLY_CORRECT", posixly_correct, 1);
926+
else
927+
unsetenv("POSIXLY_CORRECT");
928+
891929
argc -= optind;
892930
argv += optind;
893931

894932
/* default if no --log-* specified */
895933
if (!outfile && !infile) {
896-
if (argc > 0) {
934+
/* if argv[0] is not after --, use argv[0] as outfile */
935+
if (argc > 0 && strcmp(argv[-1], "--") != 0) {
897936
outfile = argv[0];
898937
argc--;
899938
argv++;
@@ -906,9 +945,29 @@ int main(int argc, char **argv)
906945
log_associate(&ctl, &ctl.out, outfile, SCRIPT_FMT_RAW);
907946
}
908947

948+
/* skip -- to non-option arguments */
949+
if (argc > 0 && strcmp(argv[0], "--") == 0) {
950+
argc--;
951+
argv++;
952+
}
953+
954+
/* concat non-option arguments as command */
955+
if (argc > 0 && strcmp(argv[-1], "--") == 0) {
956+
if (ctl.command != NULL) {
957+
warnx(_("conflicting arguments of --command and non-option arguments"));
958+
errtryhelp(EXIT_FAILURE);
959+
}
960+
961+
ctl.command = concat_command(argc, argv);
962+
if (!ctl.command)
963+
errx(EXIT_FAILURE, _("failed to concatenate arguments"));
964+
965+
ctl.command_norm = xstrdup(ctl.command);
966+
strrep(ctl.command_norm, '\n', ' ');
967+
argc = 0;
968+
}
969+
909970
if (argc > 0) {
910-
/* only one filename is accepted. if --log-out was given,
911-
* freestanding filename is ignored */
912971
warnx(_("unexpected number of arguments"));
913972
errtryhelp(EXIT_FAILURE);
914973
}

0 commit comments

Comments
 (0)