📄 subshells.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><HTML><HEAD><TITLE>Subshells</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.57"><LINKREL="HOME"TITLE="Advanced Bash-Scripting Guide"HREF="index.html"><LINKREL="UP"TITLE="Advanced Topics"HREF="part4.html"><LINKREL="PREVIOUS"TITLE="Globbing"HREF="globbingref.html"><LINKREL="NEXT"TITLE="Restricted Shells"HREF="restricted-sh.html"><METAHTTP-EQUIV="Content-Style-Type"CONTENT="text/css"><LINKREL="stylesheet"HREF="common/kde-common.css"TYPE="text/css"><METAHTTP-EQUIV="Content-Type"CONTENT="text/html; charset=iso-8859-1"><METAHTTP-EQUIV="Content-Language"CONTENT="en"><LINKREL="stylesheet"HREF="common/kde-localised.css"TYPE="text/css"TITLE="KDE-English"><LINKREL="stylesheet"HREF="common/kde-default.css"TYPE="text/css"TITLE="KDE-Default"></HEAD><BODYCLASS="CHAPTER"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#AA0000"VLINK="#AA0055"ALINK="#AA0000"STYLE="font-family: sans-serif;"><DIVCLASS="NAVHEADER"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">Advanced Bash-Scripting Guide: An in-depth exploration of the art of shell scripting</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><AHREF="globbingref.html">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom"></TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="restricted-sh.html">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="CHAPTER"><H1><ANAME="SUBSHELLS">Chapter 20. Subshells</A></H1><P><ANAME="SUBSHELLSREF"></A></P><P>Running a shell script launches another instance of the command processor. Just as your commands are interpreted at the command line prompt, similarly does a script batch process a list of commands in a file. Each shell script running is, in effect, a subprocess of the <AHREF="internal.html#FORKREF">parent</A> shell, the one that gives you the prompt at the console or in an <ICLASS="FIRSTTERM">xterm</I> window.</P><P>A shell script can also launch subprocesses. These <ICLASS="EMPHASIS">subshells</I> let the script do parallel processing, in effect executing multiple subtasks simultaneously.</P><TABLECLASS="SIDEBAR"BORDER="1"CELLPADDING="5"><TR><TD><DIVCLASS="SIDEBAR"><ANAME="AEN13908"></A><P>In general, an <AHREF="external.html#EXTERNALREF">external command</A> in a script <AHREF="internal.html#FORKREF">forks off</A> a subprocess, whereas a Bash <AHREF="internal.html#BUILTINREF">builtin</A> does not. For this reason, builtins execute more quickly than their external command equivalents.</P></DIV></TD></TR></TABLE><DIVCLASS="VARIABLELIST"><P><B><ANAME="SUBSHELLPARENS1"></A>Command List in Parentheses</B></P><DL><DT>( command1; command2; command3; ... )</DT><DD><P>A command list embedded between <TTCLASS="REPLACEABLE"><I>parentheses</I></TT> runs as a subshell.</P></DD></DL></DIV><DIVCLASS="NOTE"><TABLECLASS="NOTE"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/note.png"HSPACE="5"ALT="Note"></TD><TDALIGN="LEFT"VALIGN="TOP"><P><ANAME="PARVIS"></A>Variables in a subshell are <ICLASS="EMPHASIS">not</I> visible outside the block of code in the subshell. They are not accessible to the <AHREF="internal.html#FORKREF">parent process</A>, to the shell that launched the subshell. These are, in effect, <AHREF="localvar.html#LOCALREF">local variables</A>.</P></TD></TR></TABLE></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="SUBSHELL"></A><P><B>Example 20-1. Variable scope in a subshell</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # subshell.sh 3 4 echo 5 6 echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL" 7 # Bash, version 3, adds the new $BASH_SUBSHELL variable. 8 echo 9 10 outer_variable=Outer 11 12 ( 13 echo "Subshell level INSIDE subshell = $BASH_SUBSHELL" 14 inner_variable=Inner 15 16 echo "From subshell, \"inner_variable\" = $inner_variable" 17 echo "From subshell, \"outer\" = $outer_variable" 18 ) 19 20 echo 21 echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL" 22 echo 23 24 if [ -z "$inner_variable" ] 25 then 26 echo "inner_variable undefined in main body of shell" 27 else 28 echo "inner_variable defined in main body of shell" 29 fi 30 31 echo "From main body of shell, \"inner_variable\" = $inner_variable" 32 # $inner_variable will show as uninitialized 33 #+ because variables defined in a subshell are "local variables". 34 # Is there any remedy for this? 35 36 echo 37 38 exit 0</PRE></TD></TR></TABLE><HR></DIV><P>See also <AHREF="gotchas.html#SUBPIT">Example 31-2</A>.</P><P>+</P><P>Directory changes made in a subshell do not carry over to the parent shell.</P><DIVCLASS="EXAMPLE"><HR><ANAME="ALLPROFS"></A><P><B>Example 20-2. List User Profiles</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # allprofs.sh: print all user profiles 3 4 # This script written by Heiner Steven, and modified by the document author. 5 6 FILE=.bashrc # File containing user profile, 7 #+ was ".profile" in original script. 8 9 for home in `awk -F: '{print $6}' /etc/passwd` 10 do 11 [ -d "$home" ] || continue # If no home directory, go to next. 12 [ -r "$home" ] || continue # If not readable, go to next. 13 (cd $home; [ -e $FILE ] && less $FILE) 14 done 15 16 # When script terminates, there is no need to 'cd' back to original directory, 17 #+ because 'cd $home' takes place in a subshell. 18 19 exit 0</PRE></TD></TR></TABLE><HR></DIV><P>A subshell may be used to set up a <SPANCLASS="QUOTE">"dedicated environment"</SPAN> for a command group. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 COMMAND1 2 COMMAND2 3 COMMAND3 4 ( 5 IFS=: 6 PATH=/bin 7 unset TERMINFO 8 set -C 9 shift 5 10 COMMAND4 11 COMMAND5 12 exit 3 # Only exits the subshell. 13 ) 14 # The parent shell has not been affected, and the environment is preserved. 15 COMMAND6 16 COMMAND7</PRE></TD></TR></TABLE> One application of this is testing whether a variable is defined. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 if (set -u; : $variable) 2> /dev/null 2 then 3 echo "Variable is set." 4 fi # Variable has been set in current script, 5 #+ or is an an internal Bash variable, 6 #+ or is present in environment (has been exported). 7 8 # Could also be written [[ ${variable-x} != x || ${variable-y} != y ]] 9 # or [[ ${variable-x} != x$variable ]] 10 # or [[ ${variable+x} = x ]] 11 # or [[ ${variable-x} != x ]]</PRE></TD></TR></TABLE> Another application is checking for a lock file: <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 if (set -C; : > lock_file) 2> /dev/null 2 then 3 : # lock_file didn't exist: no user running the script 4 else 5 echo "Another user is already running that script." 6 exit 65 7 fi 8 9 # Code snippet by St閜hane Chazelas, 10 #+ with modifications by Paulo Marcel Coelho Aragao.</PRE></TD></TR></TABLE> </P><P>Processes may execute in parallel within different subshells. This permits breaking a complex task into subcomponents processed concurrently.</P><DIVCLASS="EXAMPLE"><HR><ANAME="PARALLEL-PROCESSES"></A><P><B>Example 20-3. Running parallel processes in subshells</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 (cat list1 list2 list3 | sort | uniq > list123) & 2 (cat list4 list5 list6 | sort | uniq > list456) & 3 # Merges and sorts both sets of lists simultaneously. 4 # Running in background ensures parallel execution. 5 # 6 # Same effect as 7 # cat list1 list2 list3 | sort | uniq > list123 & 8 # cat list4 list5 list6 | sort | uniq > list456 & 9 10 wait # Don't execute the next command until subshells finish. 11 12 diff list123 list456</PRE></TD></TR></TABLE><HR></DIV><P>Redirecting I/O to a subshell uses the <SPANCLASS="QUOTE">"|"</SPAN> pipe operator, as in <TTCLASS="USERINPUT"><B>ls -al | (command)</B></TT>.</P><DIVCLASS="NOTE"><TABLECLASS="NOTE"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/note.png"HSPACE="5"ALT="Note"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>A command block between <TTCLASS="REPLACEABLE"><I>curly braces</I></TT> does <ICLASS="EMPHASIS">not</I> launch a subshell.</P><P>{ command1; command2; command3; ... }</P></TD></TR></TABLE></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="globbingref.html">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="restricted-sh.html">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Globbing</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="part4.html">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Restricted Shells</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -