LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 07-11-2012, 11:05 AM   #1
porphyry5
Member
 
Registered: Jul 2010
Location: oregon usa
Distribution: Slackware 14.1, Arch, Lubuntu 18.04 OpenSUSE Leap 15.x
Posts: 518

Rep: Reputation: 24
Bash; terminate sourced script without closing its shell


What command within a sourced script will stop execution and return to it's shell's command prompt?
 
Old 07-11-2012, 11:19 AM   #2
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 21,930

Rep: Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321Reputation: 7321
basically there is no way to do this, but there are some workarounds:
inside a loop you can use break (so implement a "virtual" endless loop and you will break it for sure)
you can move all the sourced script into a function and you can return from the function any time.
 
1 members found this post helpful.
Old 07-11-2012, 11:50 AM   #3
porphyry5
Member
 
Registered: Jul 2010
Location: oregon usa
Distribution: Slackware 14.1, Arch, Lubuntu 18.04 OpenSUSE Leap 15.x
Posts: 518

Original Poster
Rep: Reputation: 24
Quote:
Originally Posted by pan64 View Post
basically there is no way to do this, but there are some workarounds:
inside a loop you can use break (so implement a "virtual" endless loop and you will break it for sure)
you can move all the sourced script into a function and you can return from the function any time.
Thank you, that's what I have been doing, but always wondered if there was a kosher method.
 
Old 07-11-2012, 12:40 PM   #4
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
When you source a file, you're essentially merging it with the parent, so that they become one single script. There isn't any boundary between them.

Sourcing, especially into an interactive shell, really is best suited for importing static data, IMO, such as variable or function definitions, or at most short conditional blocks that alter environment settings. Using it to actually run commands has always seemed rather risky to me. Is there any reason you can't just make the external file an executable script of its own, and call/control it like any other command?

Last edited by David the H.; 07-11-2012 at 12:41 PM.
 
Old 07-11-2012, 12:57 PM   #5
porphyry5
Member
 
Registered: Jul 2010
Location: oregon usa
Distribution: Slackware 14.1, Arch, Lubuntu 18.04 OpenSUSE Leap 15.x
Posts: 518

Original Poster
Rep: Reputation: 24
Quote:
Originally Posted by David the H. View Post
Is there any reason you can't just make the external file an executable script of its own, and call/control it like any other command?
None, except I use source to run scripts that I'm developing, because its variable values are still available after the script exits, which is not true of direct execution, and I know of no other way of achieving that except with "set", which buries one in its output. Its much more convenient just to do "echo $varname" for debugging purposes.
 
Old 07-11-2012, 01:03 PM   #6
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
Set the variables in the main shell first, and export them. Then they'll be visible to your script too.

Frankly, I just set the variables in the script itself, otherwise you have to keep track of where the values are coming from, and that can get confusing when writing a long script. I also always just have two or more consoles open at once; one for writing and one for testing.

Last edited by David the H.; 07-11-2012 at 01:06 PM.
 
Old 07-11-2012, 01:04 PM   #7
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,187

Rep: Reputation: 354Reputation: 354Reputation: 354Reputation: 354
You should think of a sourced file as though it was an "include" in a compiled program. That is, since bash in an interpreted language, no a compiled one, the source command just pushes the current input down the input stack and adds whatever you've "sourced," to the top of the input stack. It will happily read from that "source" until the EOF is hit, after which the prior "source" is popped from the stack and input from it is resumed.

I almost never use sourced files for anything but function definitions, which I keep in /usr/share/bash. Here's a typical use:
Code:
$ cat /etc/rc.d/rc.local
#!/bin/sh
# Load the local function definitions
. /usr/share/bash/include
include define_colors sucmd connect_using_nmcli_to vg_activate mount_noauto mount_cifs mount_iso
echo
echo -----------------------------------------------------
echo Starting $0

# Connect to the Eathernet network if it's available
connect_using_nmcli_to System
#connect_using_wicd

# Activate and mount any available, unmounted, volume groups with mount points in /etc/fstab
vg_activate

# Mount any "noauto" or "nofail" devices listed in /etc/fstab that exist and are not already mounted
mount_noauto

# Mount any "noauto" cifs devices
mount_cifs

# Mount up to max_loop ISO files located in /ISO under /mnt/ISO/
mount_iso
echo -----------------------------------------------------
echo
and my definition of my include function and an example of two functiona:
Code:
$ cd /usr/share/bash/
$ ls
bash_alias.sh           define_colors         mount_cifs    Ping         wait_for_connection
connect_using_nmcli_to  define_console_codes  mount_iso     sucmd
connect_using_wicd      include               mount_noauto  vg_activate
$ cat include 
#!/bin/bash
#
# Note: This bash script is symlinked as /usr/local/bin/include
#
# Define the function to include all the programs listed in "$*" from /usr/share/bash
#
# Usage: include function1 {function2 ...}
#
# Note: The function assumes that any function to be included is an executable script,
#       and searched $PAQTH for any match before looking in /usr/share/bash
#
# Define the include function if it's not already defined
if [ "$(type -t include)" != "function" ]
then
  include ()
  {
    local f abort loc
    abort=0
    for f in $*
    do
      loc=$(type -P ${f})
      if [ -z "${loc}" ]
      then
        if ! [ -e "/usr/share/bash/${f}" ]
        then
          echo Error: The bash include file \""/usr/share/bash/${f}"\" could not be found. > /dev/stderr
          $((++abort))
        else
          loc="/usr/share/bash/${f}"
        fi
      if [ -x "${loc}" ]
      then
        . "${loc}"
      else
        echo Error: The bash include file \""${loc}"\" is not executable. > /dev/stderr
        $((++abort))
      fi
    fi
    done
    [ ${abort} -gt 0 ] && echo "${abort} files could not be found in /usr/share/bash." > /dev/stderr
    return ${abort}
  }
fi
# Sanity checks:
#
# Do we have any arguments?
#
if [ $# -gt 0 ]
then
  include "$*"
else
  cat <<EOF >/dev/stderr
include: Usage "include file {file . . .}

where "file . . ." are executable files in /usr/share/bash to be sourced in the script.

EOF
fi
$ cat sucmd
#############################################################################
#
# Run a command as "root" and return its returned value
#
#############################################################################
sucmd() {
  local error_code
  # Make sure the color codes are defined
  [ -z "${csi}" ] && define_colors
  if [ $(id -u) -eq 0 ]
  then
    sucmd=
  else
    sucmd="sudo"
  fi
  echo -n ${bold_blue}
  ${sucmd} $*
  error_code=$?
  echo -n ${reset}
  return ${error_code}
}
$ cat define_colors 
####################################################################################
#
# Console code definitions (foreground colors only)
#
# See man console_codes for a full description
#
####################################################################################
define_colors()
{
  csi=$'\x1B['
  reset="${csi}0m"
  bold="${csi}1m"
  black="${csi}30m"
  red="${csi}31m"
  green="${csi}32m"
  brown="${csi}33m"
  blue="${csi}34m"
  magenta="${csi}35m"
  cyan="${csi}36m"
  white="${csi}37m"
  bold_red="${bold}${red}"
  bold_green="${bold}${bold_green}"
  bold_brown="${bold}${brown}"
  bold_blue="${bold}${blue}"
  bold_magenta="${bold}${magenta}"
  bold_cyan="${bold}${cyan}"
  underscore_on="${csi}38m"
  underscore_off="${csi}39m"
}
 
Old 07-11-2012, 01:46 PM   #8
porphyry5
Member
 
Registered: Jul 2010
Location: oregon usa
Distribution: Slackware 14.1, Arch, Lubuntu 18.04 OpenSUSE Leap 15.x
Posts: 518

Original Poster
Rep: Reputation: 24
Quote:
Originally Posted by David the H. View Post
Set the variables in the main shell first, and export them. Then they'll be visible to your script too.

Frankly, I just set the variables in the script itself, otherwise you have to keep track of where the values are coming from, and that can get confusing when writing a long script. I also always just have two or more consoles open at once; one for writing and one for testing.
Not sure if we are talking at cross purposes here. Its the variables within the script that is executing that I'm interested in. If it terminates exceptionally, their final values are still available if source was used, and usually one can debug the situation with no other reference. I believe this is so because source still holds the shell in which the script executed open, and it is a great convenience.
 
Old 07-11-2012, 02:08 PM   #9
porphyry5
Member
 
Registered: Jul 2010
Location: oregon usa
Distribution: Slackware 14.1, Arch, Lubuntu 18.04 OpenSUSE Leap 15.x
Posts: 518

Original Poster
Rep: Reputation: 24
Quote:
Originally Posted by PTrenholme View Post
You should think of a sourced file as though it was an "include" in a compiled program. That is, since bash in an interpreted language, no a compiled one, the source command just pushes the current input down the input stack and adds whatever you've "sourced," to the top of the input stack. It will happily read from that "source" until the EOF is hit, after which the prior "source" is popped from the stack and input from it is resumed.
I'm not understanding the objection to my using source the way I do. If it is a security issue, it doesn't exist for me, I am the sole user of my home computers, and my scripts are only ever run as user. My only affection for "source" is that it makes debugging so much more convenient than anything else I know. If there is an alternative method of testing scripts as convenient as "source", I'm quite willing to use it, but I don't know of any such. All I want is for the script's final variable values to be still available when the script terminates.
 
Old 07-12-2012, 09:22 AM   #10
Reuti
Senior Member
 
Registered: Dec 2004
Location: Marburg, Germany
Distribution: openSUSE 15.2
Posts: 1,339

Rep: Reputation: 260Reputation: 260Reputation: 260
It depends on your sourced script. Don’t use exit anywhere, but set a variable in case you want to exit and use it in upcoming if-then-else to avoid any further execution. Somehow I remember doing this for Pascal functions to get to the end.
 
1 members found this post helpful.
Old 07-12-2012, 10:18 AM   #11
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
Quote:
Originally Posted by porphyry5 View Post
Not sure if we are talking at cross purposes here. Its the variables within the script that is executing that I'm interested in. If it terminates exceptionally, their final values are still available if source was used, and usually one can debug the situation with no other reference. I believe this is so because source still holds the shell in which the script executed open, and it is a great convenience.
Yeah, my bad. Chock it up to drowsiness; it was my final post before crashing last night, and I was thinking in terms of input rather than output.

I agree then that it does offer some convenience, but as another option you might consider outputting them into a textfile instead. A quick "declare > file" at the end of the script, or a similar debugging function, should do it. Then it's just a quick less or grep to view them.
 
1 members found this post helpful.
Old 07-12-2012, 10:45 AM   #12
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,187

Rep: Reputation: 354Reputation: 354Reputation: 354Reputation: 354
Quote:
Originally Posted by porphyry5 View Post
I'm not understanding the objection to my using source the way I do. If it is a security issue, it doesn't exist for me, I am the sole user of my home computers, and my scripts are only ever run as user. My only affection for "source" is that it makes debugging so much more convenient than anything else I know. If there is an alternative method of testing scripts as convenient as "source", I'm quite willing to use it, but I don't know of any such. All I want is for the script's final variable values to be still available when the script terminates.
That's a good reason to use shell functions. Inside the function you can declare any variables you don't want to return as local, and any other variables you use will be available to the rest of your program. All this without needing to export the variables or, in fact, anything else.

The advantage of the "function" method is that, once you get the function debugged, you can pop it into a function library and either source it or (my preference) use something like my include function above to source in whatever you want from your library.
 
Old 07-13-2012, 10:31 AM   #13
porphyry5
Member
 
Registered: Jul 2010
Location: oregon usa
Distribution: Slackware 14.1, Arch, Lubuntu 18.04 OpenSUSE Leap 15.x
Posts: 518

Original Poster
Rep: Reputation: 24
Quote:
Originally Posted by David the H. View Post
Yeah, my bad. Chock it up to drowsiness; it was my final post before crashing last night, and I was thinking in terms of input rather than output.

I agree then that it does offer some convenience, but as another option you might consider outputting them into a textfile instead. A quick "declare > file" at the end of the script, or a similar debugging function, should do it. Then it's just a quick less or grep to view them.
Thank you, that works very well, though better with grep than less.
 
Old 07-13-2012, 11:54 AM   #14
porphyry5
Member
 
Registered: Jul 2010
Location: oregon usa
Distribution: Slackware 14.1, Arch, Lubuntu 18.04 OpenSUSE Leap 15.x
Posts: 518

Original Poster
Rep: Reputation: 24
Quote:
Originally Posted by PTrenholme View Post
That's a good reason to use shell functions. Inside the function you can declare any variables you don't want to return as local, and any other variables you use will be available to the rest of your program. All this without needing to export the variables or, in fact, anything else.

The advantage of the "function" method is that, once you get the function debugged, you can pop it into a function library and either source it or (my preference) use something like my include function above to source in whatever you want from your library.
I can write the entire script as a function, paste the text of it into xterm and run the function name and all is well. But the last script I wrote exceeded 170 lines, which is rather unwieldy to select and paste, and I can't find any command other than "source" or its alias "." that will load it into the shell. I tried running it as an executable file containing just the function itself, and also preceded with a shebang line as usual, but they of course ran in their own subshells, so the function was not available back in the main shell when I tried to use it.
Code:
~ $ cat ~/Scripts/junk.sh
junk(){
a=6
c=7
b=8
}
~ $ ~/Scripts/junk.sh
~ $ junk
bash: junk: command not found
# put shebang line back in junk.sh and tried again
~ $ ~/Scripts/junk.sh
~ $ junk
bash: junk: command not found
~ $
I could use xsel and xdotool to physically paste the content of junk.sh into xterm, but why do something so long-winded when I can just use "."

Unless they're really trivial, in which case I do them as functions in ~/.bashrc, I develop and test all my scripts as junk.sh, and run them via
Code:
alias j='source /home/g/Scripts/junk.sh'
Hard to make it more convenient than that, so absent some compelling reason to abandon "source" ...
 
Old 07-13-2012, 12:09 PM   #15
porphyry5
Member
 
Registered: Jul 2010
Location: oregon usa
Distribution: Slackware 14.1, Arch, Lubuntu 18.04 OpenSUSE Leap 15.x
Posts: 518

Original Poster
Rep: Reputation: 24
Quote:
Originally Posted by Reuti View Post
It depends on your sourced script. Don’t use exit anywhere, but set a variable in case you want to exit and use it in upcoming if-then-else to avoid any further execution. Somehow I remember doing this for Pascal functions to get to the end.
I use a variable to control subsequent flow when inside an inner loop and arrive at a condition that requires breaking the outer loop as well, or it could be extended to a chain of them if need be. But to break from just a single loop its easier to use break by itself.
 
  


Reply



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
How do I make my BASH script yes/no user input query terminate with 3 invalid inputs? lupusarcanus Linux - Newbie 9 03-16-2010 03:43 PM
in bash shell how to run shell script during startup rammohan04 Red Hat 2 07-31-2009 02:07 AM
How to terminate Bash Script if remote session disconnects zia.hassan Linux - Newbie 4 06-15-2009 04:04 AM
how can a shell script determine its own location when being sourced? DeuceNegative Linux - Software 5 02-21-2008 01:57 PM
How to run script that doesn't terminate when shell closes? bjdea1 Linux - General 2 09-20-2004 10:20 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:59 PM.

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
Open Source Consulting | Domain Registration