perl_007 has asked for the wisdom of the Perl Monks concerning the following question:

I'm new to perl scripting and trying to source .bash_profile file and then do cd to the directory. below is the content of the .bash_profile file:

# .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs export CTC_HOME=/Inf/work/ #PATH=$PATH:$HOME/.local/bin:$HOME/bin #export PATH

below is the script i'm trying to create:

#!/bin/perl # use strict; use warnings; if(-s "/cs/ctc/.bash_profile"){ `source ~/.bash_profile`; }else { print "The file doesnot exists","\n"; exit 1; } my $dir = "cd $CTC_HOME"; chdir($dir);

But, getting below error:

Global symbol "$CTC_HOME" requires explicit package name at ./program. +pl line 12. Execution of ./program.pl aborted due to compilation errors.
Any help is most welcome!!!

Replies are listed 'Best First'.
Re: source a file in Linux using perl script
by Corion (Pope) on Nov 30, 2020 at 07:21 UTC

    The environment variables of the shell are available through the %ENV hash in Perl. See perlvar for it.

    The easiest way to make the variables available to a Perl script is to set them up beforehand:

    #!/bin/bash . ~/.bash_profile /path/to/your/perlscript.pl

    If that is not possible, you can follow the approach outlined in Get default login environment to get the environment variables that the script sets up. Specifically, RE (tilly) 3: Get default login environment has a subroutine that does what you want.

      TIMTOWTDI:
      #!/usr/bin/perl use POSIX; use String::ShellQuote qw(shell_quote); unless (defined $ENV{CTC_HOME}) { $ENV{DONT_LOOP_FOREVER}++ or die "infinite loop detected"; exec "source ~/.bash_profile && ".shell_quote($^X, $0, @ARGV); POSIX::_exit(255); } chdir($ENV{CTC_HOME}); ...

      Though, I have to admit I prefer the simpler shell wrapper solution given by Corion.

        I think the one drawback of re-executing yourself like that is that you lose Perl command line switches like -Ilib etc. ... There is Devel::PL_origargv, which gives you the original command line, but I'm not sure that I would want to go such an esoteric length when a shell script can do the same.

Re: source a file in Linux using perl script
by Fletch (Chancellor) on Nov 30, 2020 at 14:48 UTC

    Just a note as to why you're getting these other solutions: when you're using backticks or system or whatever to run your source command a completely new shell is starting up, running the commands in the source'd script and changing that new shell's environment, and then that shell exits and any modifications disappear. The *NIX process model doesn't allow a child process to modify its parent's environment (as is noted in perlfaq8, "I {changed directory, modified my environment} in a perl script. How come the change disappeared . . .?" )

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: source a file in Linux using perl script
by LanX (Cardinal) on Nov 30, 2020 at 10:06 UTC
Re: source a file in Linux using perl script
by LanX (Cardinal) on Nov 30, 2020 at 12:00 UTC
    > I'm new to perl scripting

    Hm ... probably it's much easier, and you are just missing the obvious. ..

    ... please check if your environment was already set from your parent process, before trying the other workarounds.

    print $ENV{CTC_HOME}

    See also %ENV

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Re: source a file in Linux using perl script
by perlfan (Vicar) on Nov 30, 2020 at 18:20 UTC
    Your execution environment inherits the environment set up via ~/.bash_profile. I recommend you not try to source that file in the script. If you need to access the environment and manipulate it, you do so via %ENV. Then anything you run under that perl process will inherit this environment. A child process can't affect the parent process's (e.g., bash shell) environment once the process is complete. In other words, you can't use a script or program to update the environment of the shell in a persistent way (after the perl script has exited).

    If you wish to make CTC_HOME available as part of the environment in your script you can update %ENV in the code:

    use strict; use warnings; local %ENV = %ENV; # NOTE: local is used here in case you wish to # restore the original %ENV in a different scope # of this script $ENV{CTC_HOME} = q{/Inf/work/}; # ... now "CTC_HOME" is available for all child # processes (via fork, system, ``, etc) of $0 (this script)

    Given this idiom, you could then pass in CTC_HOME as a commandline argument or, better still, as a configuration file that you can then parse via Config::Tiny. That said, you could also just make sure the environment is set up as you wished via ~/.bash_profile before execution to avoid all of this. I am still not sure why you want to effect ~/.bash_profile. It almost seems like you're wishing to ensure an environment via command invoked via ssh. In this case, note that ssh has options that allow you to pass remote environmental viariables via the ssh command itself.