LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 11-27-2012, 09:30 AM   #1
bashMe
LQ Newbie
 
Registered: Nov 2012
Posts: 9

Rep: Reputation: Disabled
Post PS1: not working in .sh files, and why use 'export'?


The following works at the command line:
Code:
PS1=">> "
But when I include the above in a bash script (let's call it, promptChange.sh), my prompt doesn't change whe I execute it.

Note even if I enter the following in promptChange.sh:
Code:
export PS1=">> "
it does not change my prompt.

Note when I add the previous to my .bashrc file, it works fine, but I am still confused in two ways:

1. When you execute a shell file, it is just as if you entered the text at the command line. If so, why am I not able to change my prompt using promptChange.sh?

2. What is the difference between
[1]
Code:
PS1=">>"
and
[2]
Code:
export PS1=">>"
I know 'export' is supposed to set environment variables, but I am confused about the difference between [1] and [2], and whether 'export' is needed at all? When I insert line [1] in .bashrc it seems to work just fine, so are [1] and [2] technically equivalent, and if so, is there a reason I should prefer [2]?
 
Old 11-27-2012, 09:42 AM   #2
suicidaleggroll
LQ Guru
 
Registered: Nov 2010
Location: Colorado
Distribution: OpenSUSE, CentOS
Posts: 5,258

Rep: Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947
1) Executing a shell script is NOT the same as entering the commands on the command line. When you execute a shell script, it runs in its own subshell. The parent does not have access to any variables, even environment variables, created inside that subshell since once it exits, it's gone. You need to SOURCE the script if you want it to execute in your current shell, and retain the values of any variables set within. Your .bashrc script is sourced on login, which is why your command works there. You can source the script by either running "source script.sh" or ". script.sh".

2) When you export a variable, it makes that variable and its contents available to any program launched from that shell. Conversely, regular variables are only accessible by that shell.
 
1 members found this post helpful.
Old 11-27-2012, 10:54 AM   #3
shivaa
Senior Member
 
Registered: Jul 2012
Location: Grenoble, Fr.
Distribution: Sun Solaris, RHEL, Ubuntu, Debian 6.0
Posts: 1,800
Blog Entries: 4

Rep: Reputation: 286Reputation: 286Reputation: 286
(1) It is way to define a variable in bash shell:
Code:
VARIABLE=<value>
export VARIABLE
(2) You should use export to the newly defined variable to take it into effect.
(3) Both PS1=">> " and export PS1=">> " do the same job on command line. But if you're using it in a script, you should use export PS1=">> ", and then you'll need to source the script file, as follow:
Code:
source promptChange.sh
(4) So whenever you want to change your prompt, simply source the script file. BTW, the file that you're sourcing need not to be a shell script, but can be a simple text file, while sourcing it using source cmd.

Last edited by shivaa; 11-27-2012 at 10:57 AM.
 
1 members found this post helpful.
Old 11-27-2012, 11:02 AM   #4
bashMe
LQ Newbie
 
Registered: Nov 2012
Posts: 9

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by suicidaleggroll View Post
1) Executing a shell script is NOT the same as entering the commands on the command line. When you execute a shell script, it runs in its own subshell. The parent does not have access to any variables, even environment variables, created inside that subshell since once it exits, it's gone. You need to SOURCE the script if you want it to execute in your current shell, and retain the values of any variables set within. Your .bashrc script is sourced on login, which is why your command works there. You can source the script by either running "source script.sh" or ". script.sh".

2) When you export a variable, it makes that variable and its contents available to any program launched from that shell. Conversely, regular variables are only accessible by that shell.
Thanks that is very helpful. Putting it in terms I am used to from Matlab: 1 seems analogous to invoking local variables within a function that are erased once you leave the function. And re:2 seems akin to defining a global variable. I'm sure that's not quite right, but will it hurt me to think in these terms for now until I get up to speed with subshells and such?

Sorry I am literally on chapter 1 of my text, so I don't even know how to talk about this stuff in literal terms yet...

Last edited by bashMe; 11-27-2012 at 12:00 PM.
 
Old 11-27-2012, 11:57 AM   #5
suicidaleggroll
LQ Guru
 
Registered: Nov 2010
Location: Colorado
Distribution: OpenSUSE, CentOS
Posts: 5,258

Rep: Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947
Quote:
Originally Posted by bashMe View Post
Thanks that is very helpful. Putting it in terms I am used to from Matlab: 1 seems analogous to invoking local variables within a function that are erased once you leave the function. And re:2 seems akin to defining a global variable. I'm sure that's not quite right, but will it hurt me to think in these terms for now until I get up to speed with subshells and such?
That's pretty similar, however be careful with that train of thought, because shells also have local/global variables that operate differently than environment variables.

As an example of #2, open a terminal emulator (gnome-terminal, konsole, etc), and run the following:
Code:
var1=val1
export var2=val2
Then from within that shell, launch another by running "gnome-terminal", "konsole", "xterm", or whatever other terminal emulator you like. Inside this new one, run:
Code:
echo $var1
echo $var2
You'll see that only var2 still contains its original contents, because var1 was just a regular variable local to the first shell, while var2 is an environment variable accessible by anything spawned by that original shell (it's "children").

Child processes will inherit all environment variables from their parent, but parent processes will NOT inherit any variables, environment or otherwise, from their children.

One of the important differences between environment variables and other shell variables, is that environment variables are accessible by ANYTHING spawned by that shell, not just other shells or functions, but Fortran programs, C programs, Java programs...anything run in that shell has access to those environment variables.

Last edited by suicidaleggroll; 11-27-2012 at 12:03 PM.
 
1 members found this post helpful.
Old 11-27-2012, 12:03 PM   #6
bashMe
LQ Newbie
 
Registered: Nov 2012
Posts: 9

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by suicidaleggroll View Post
That's pretty much it. However be careful with that train of thought, since shells also have global variables, which do not operate the same as environment variables.
Yes, that's what I thought.


Quote:
Originally Posted by suicidaleggroll View Post
As an example of #2, open a terminal emulator (gnome-terminal, konsole, etc), and run the following:
Code:
var1=val1
export var2=val2
Then from within that shell, launch another by running "gnome-terminal", "konsole", "xterm", or whatever other terminal emulator you like. Inside this new one, run:
Code:
echo $var1
echo $var2
You'll see that only var2 still contains its original contents, because var1 was just a regular variable local to the first shell, while var2 is an environment variable accessible by anything spawned by that original shell (it's "children").

Child processes will inherit all environment variables from their parent, but parent processes will NOT inherit any variables, environment or otherwise, from their children.

One of the important differences between environment variables and other shell variables, is that environment variables are accessible by ANYTHING spawned by that shell, not just other shells or functions, but Fortran programs, C programs, Java programs...anything run in that shell has access to those environment variables.
Cool! So it's almost like a super-global variable.
 
Old 11-27-2012, 12:05 PM   #7
bashMe
LQ Newbie
 
Registered: Nov 2012
Posts: 9

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by shivaa View Post
(1) It is way to define a variable in bash shell:
Code:
VARIABLE=<value>
export VARIABLE
(2) You should use export to the newly defined variable to take it into effect.
(3) Both PS1=">> " and export PS1=">> " do the same job on command line. But if you're using it in a script, you should use export PS1=">> ", and then you'll need to source the script file, as follow:
Code:
source promptChange.sh
(4) So whenever you want to change your prompt, simply source the script file. BTW, the file that you're sourcing need not to be a shell script, but can be a simple text file, while sourcing it using source cmd.
Thanks. I don't know what sourcing a script is, but I assume it will become more clear to me as I move past chapter 2, and I will presently go Google it just to get a tenth of a clue.
 
Old 11-27-2012, 12:11 PM   #8
suicidaleggroll
LQ Guru
 
Registered: Nov 2010
Location: Colorado
Distribution: OpenSUSE, CentOS
Posts: 5,258

Rep: Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947Reputation: 1947
Quote:
Originally Posted by bashMe View Post
Thanks. I don't know what sourcing a script is, but I assume it will become more clear to me as I move past chapter 2, and I will presently go Google it just to get a tenth of a clue.
Sourcing a script is akin to copy-pasting its contents and running them in your current shell, rather than spawning a subshell to run the script.

As an example, create a script with the following contents:
Code:
var3=3
export var4=4
echo "var1: $var1"
echo "var2: $var2"
echo "var3: $var3"
echo "var4: $var4"
Then from your shell, run
Code:
var1=1
export var2=2
./script.sh
echo $var1 $var2 $var3 $var4
Then from a separate shell, run
Code:
var1=1
export var2=2
source script.sh
echo $var1 $var2 $var3 $var4
Hopefully that'll make it clear how sourcing is different than spawning a process in a subshell.

Last edited by suicidaleggroll; 11-27-2012 at 12:14 PM.
 
1 members found this post helpful.
Old 11-27-2012, 08:21 PM   #9
bashMe
LQ Newbie
 
Registered: Nov 2012
Posts: 9

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by suicidaleggroll View Post
Sourcing a script is akin to copy-pasting its contents and running them in your current shell, rather than spawning a subshell to run the script.
[...]
Hopefully that'll make it clear how sourcing is different than spawning a process in a subshell.
Great stuff! Thanks for all the help. I'd say my problem is solved.
 
Old 11-28-2012, 12:07 PM   #10
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957Reputation: 1957
Quote:
Originally Posted by suicidaleggroll View Post
One of the important differences between environment variables and other shell variables, is that environment variables are accessible by ANYTHING spawned by that shell, not just other shells or functions, but Fortran programs, C programs, Java programs...anything run in that shell has access to those environment variables.
I don't believe this is quite true. The only differences between user variables and environment variables are that a) the latter are generally pre-defined and b) they are exported by default (and some are set to read-only). In all other aspects they are the same.

The only purpose of export is to make the value available to sub-processes. Without it they are generally limited to the current shell environment, as demonstrated previously.

However...

The bash man page has a section called COMMAND EXECUTION ENVIRONMENT that details how the environment is defined in different situations. Notice in particular that there's a difference between a sub-process and a subshell.

Quote:
When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following. Unless otherwise noted, the values are inherited from the shell.

the shell's open files, plus any modifications and additions specified by redirections to the command
the current working directory
the file creation mode mask
shell variables and functions marked for export, along with variables exported for the command, passed in the environment
traps caught by the shell are reset to the values inherited from the shell's parent, and traps ignored by the shell are ignored

A command invoked in this separate environment cannot affect the shell's execution environment.

Command substitution, commands grouped with parentheses, and asynchronous commands are invoked in a subshell environment that is a duplicate of the shell environment, except that traps caught by the shell are reset to the values that the shell inherited from its parent at invocation. Builtin commands that are invoked as part of a pipeline are also executed in a subshell environment. Changes made to the subshell environment cannot affect the shell's execution environment.
So a subshell will inherit all values, exported or not, but most other commands will only inherit exported values.

Finally, the usual way to create a command that needs to change the original environment is to write it up as a shell function. Since these exist in and run in the current environment, they are capable of affecting it directly.

Code:
function promptchange() {
	case $1 in

		 caret) export PS1=">> " ;;
		dollar) export PS1="$$ " ;;
		  hash) export PS1="## " ;;
		     *) echo "Unknown option" >&2 ;;

	esac
}
Just set it up in your .bashrc to make it available as a permanent command.
 
1 members found this post helpful.
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Rarely used PS1 attributes - not working cryingthug Programming 7 06-20-2012 07:11 AM
[SOLVED] Ksh93 vs. Pdksh88: Custom PS1 prompt not working kristo5747 Linux - Newbie 1 01-19-2011 12:55 PM
how to export djvu files to pdf files sagsriv Linux - Software 2 08-24-2008 12:23 PM
\$ in Bash's PS1 not working for root SlowCoder Linux - General 3 05-28-2008 01:06 PM
export is not working in .bashsrc konathamsrinu Programming 14 11-03-2006 04:21 PM


All times are GMT -5. The time now is 02:57 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration