-1

How do I display basic variables like SECONDS inside Perl while running command in bash?

perl -e 'system(bash -c echo $SECONDS)'

It displays nothing at all. I have no access to the bash variables, but I am running a Perl command in bash.

Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • 5
    This smells like an [XY problem](http://mywiki.wooledge.org/XyProblem). What is it that you’re _really_ trying to achieve? – Biffen Jun 21 '23 at 07:23
  • 1
    I don’t think `$SECONDS` is exported (because that wouldn’t make any sense), so Perl won’t see it. But if I understand correctly you’re running Bash inside Perl inside Bash. Which Bash’s `$SECONDS` do you want? – Biffen Jun 21 '23 at 07:25
  • Why wouldn't it make sense to print seconds? I am obviously running Perl inside the bash. And therefore I want to use bash. I don't want to reinvent the wheel every time. – CuriousPanda Jun 21 '23 at 07:39
  • 1
    What would the exported value of `$SECONDS` be, since it changes all the time? When you run `system(bash -c echo $SECONDS)`, do you want `$SECONDS` to be expanded by (the outer) Bash, by Perl or by (the inner) Bash? If it‘s the last option, then won’t it always print `0`? And if it’s not, then why are you calling Bash (again) at all?! – Biffen Jun 21 '23 at 07:49
  • That's the core of programming, that you get a non-static value from variable and can return the value between different programs, programming languages and system. Everything else is pointless. – CuriousPanda Jun 21 '23 at 07:56
  • @CuriousPanda A common way to share a variable between programs, especially processes that are parent and child, is environment variables. A parent can export a variable for a child to read, but once exported it holds a _static_ value. `$SECONDS` in Bash is a ‘special’ variable whose value changes all the time. Not all variables are exported (they’re variables, but not _environment_ variables), and _I_ don’t think it makes much sense to export `$SECONDS`. But once again; what are you trying to achieve? – Biffen Jun 21 '23 at 08:00
  • 2
    SECONDS reports the number of seconds since `bash` started, so it will be zero if you start a new `bash` process that prints it... which seems pointless. What are you actually trying to do? – Mark Setchell Jun 21 '23 at 08:08
  • 2
    @CuriousPanda I think there is some confusion here. The bash variable `SECONDS` indicates how long the current bash-invocation is running. Calling this variable within a different bash-child does not make much sense from a programmatic point of view as a child should never know how old it's parent is. Furthermore, `SECONDS` is a special variable that only gets updated when referenced within the bash-invocation. So even by exporting it, it would be incorrect. What you could do is pass the content of `SECONDS` at the start of the perl invocation to perl, and in perl, add the perl runtime to it. – kvantour Jun 21 '23 at 08:12
  • `time - $^T` will give you the seconds since *perl* started, which you can then combine with an exported bash `SECONDS` variable to get the total time that has passed since the bash script that launched the perl script started. Not sure how else it could be useful to have available. – Shawn Jun 21 '23 at 08:12
  • The immediate problem with your code is that both `system()` and `bash -c` need to be passed single strings, which need to be quoted... and since there's going to be a string (the bash command passed to `bash -c`) inside a string (the arg to `system()`) inside a string (the perl script passed to `perl -e`) the quotes and escapes get messy: `perl -e 'system("bash -c \"echo \$SECONDS\"")'`. But, as @Biffen pointed out this just prints "0", since the new instance of bash that `system()` creates has been running for 0 seconds. So the real question is, what are you actually trying to accomplish? – Gordon Davisson Jun 21 '23 at 08:21
  • 1
    `system(bash -c echo $SECONDS)` is not even valid Perl. It would invoke a function names `bash`. You should get a syntax error from this. – user1934428 Jun 21 '23 at 08:29
  • I don't see what "needs details or clarity" here (reason for closing) -- They want to be able to use (pre-defined) bash variables in a Perl subprocess ... looks clear to me? It's so clear in fact that similar questions have been asked many times and this is probably a dupe, but then we should find a corresponding page (for how to use _defined shell variables_, not just any) and close it that way. In the meanwhile, voting to reopen – zdim Jun 28 '23 at 18:06

1 Answers1

2

A bash variable need be exported so that a Perl program, executed in that same bash process, can see it. Then you can use it in Perl as an environment variable, or in a subshell

echo $SECONDS                                    # 14  (newly opened terminal)
export SECONDS

perl -wE'say $ENV{SECONDS}'                      # 23

perl -wE'system "bash", "-c", "echo \$SECONDS"'  # 23

Note that the $ character need be escaped otherwise the Perl program will consider the $SECONDS to be a variable of its own. and will try to evaluate it (to no avail) before it passes arguments to system for a shell that it starts.


The question was raised of how to pass this only to that one program. Then pass the value as a command-line argument to the Perl program? See how to pass shell variables to Perl one-liners for example here.

Yet another way to make this value available only to the invoked program, contributed by Cyrus in a comment, is

SECONDS=$SECONDS perl -wE'say $ENV{SECONDS}'

Also, now once a new variable is introduced one can name it more suitably for the Perl program, since it won't anymore behave like the bash's SECONDS. Like

SHELL_ELAPSED=$SECONDS perl -wE'say $ENV{SHELL_ELAPSED}'
zdim
  • 64,580
  • 5
  • 52
  • 81
  • I know the export trick, but isn't that a security risk? I want to pass the command aka variable aka string only to specific process, not all processes. The problem is really that one can only work with strings. – CuriousPanda Jun 21 '23 at 08:06
  • 1
    @CuriousPanda "_I want to pass the command aka variable aka string only to specific process..._" -- Can pass it as an (command-line) argument to that specific program then? Otherwise, local variables aren't seen in a subshell -- have to export them (make them global) – zdim Jun 21 '23 at 08:20
  • @Shawn "_missing a closing single quote_" -- indeed, thank you, fixed – zdim Jun 21 '23 at 08:20
  • 1
    @CuriousPanda Also, if you elaborate on what you need `SECONDS` for in the Perl program (by editing the question is best) I can expand this answer accordingly – zdim Jun 21 '23 at 08:23
  • @CuriousPanda "_I know the export trick, but isn't that a security risk?_" -- exporting a variable need not be a security problem. Exporting functions has a history of that kind, since it was written as a command string in a variable, but then that was changed ... still, exporting a function _can_, perhaps and under specific circumstances, be exploited. I am not aware of a specific (and realistic) possibility for a problem with exporting a variable/ – zdim Jun 21 '23 at 08:28
  • `SECONDS=$SECONDS perl ...`? – Cyrus Jun 21 '23 at 08:44
  • @Cyrus ... you mean define the variable at the same line etc? Yeah, can do that too, and only this program sees it. That answers their follow-up question – zdim Jun 21 '23 at 08:48
  • @CuriousPanda See the solution from Cyrus in a comment just above -- define a variable and _at the same line_ (no semicolons or such!) invoke the program. That way the value for `SECONDS` is made available in the Perl program, and only in that program – zdim Jun 21 '23 at 08:50
  • @CuriousPanda And once we are defining a variable you can now name it more suitably than `SECONDS` for Perl (since it won't behave like bash's `SECONDS` does anymore) – zdim Jun 21 '23 at 08:54
  • @Cyrus Added that to the answer, thank you – zdim Jun 21 '23 at 08:58
  • @CuriousPanda Added to the answer. Fyi, I had also added a link to another post that shows ways to pass a shell variables to a Perl command-line program ("one-liner") – zdim Jun 21 '23 at 08:59