Learning_the_bash_Shell_Third_Edition 14/n

Chapter 7

Input/Output and Command-Line Processing

 I/O Redirectors

The redirector <> is mainly meant for use with device files (in the /dev directory), i.e., files that correspond to hardware devices such as terminals and communication lines. Low-level systems programmers can use it to test device drivers; otherwise, it’s not very useful.

Redirector

Function

cmd1 | cmd2 Pipe; take standard output of cmd1 as standard input to cmd2.
> file Direct standard output to file.
< file Take standard input from file.
>> file Direct standard output to file; append to file if it already exists.
>| file Force standard output to file even if noclobber is set.
n>| file Force output to file from file descriptor n even if noclobber is set.
<> file Use file as both standard input and standard output.
n<> file Use file as both input and output for file descriptor n.
<< label Here-document; see text.
n> file Direct file descriptor n to file.
n< file Take file descriptor n from file.
n>> file Direct file descriptor n to file; append to file if it already exists.
n>& Duplicate standard output to file descriptor n.
n<& Duplicate standard input from file descriptor n.
n>&m File descriptor n is made to be a copy of the output file descriptor.
n<&m File descriptor n is made to be a copy of the input file descriptor.
&>file Directs standard output and standard error to file.
<&- Close the standard input.
>&- Close the standard output.
n>&- Close the output from file descriptor n.
n<&- Close the input from file descriptor n.
n>&word

If n is not specified, the standard output (file descriptor 1) is used. If the digits in word do not specify a file descriptor open for output, a redirection error occurs. As a special case, if n is omitted, and word does not expand to one or more digits, the standard output and standard error are redirected as described previously.

n<&word

If word expands to one or more digits, the file descriptor denoted by n is made to be a copy of that file descriptor. If the digits in word do not specify a file descriptor open for input, a redirection error occurs. If word evaluates to -, file descriptor n is closed. If n is not specified, the standard input (file descriptor 0) is used.

n>&digit-

Moves the file descriptor digit to file descriptor n, or the standard output (file descriptor 1) if n is not specified.

n<&digit-

Moves the file descriptor digit to file descriptor n, or the standard input (file descriptor 0) if n is not specified. digit is closed after being duplicated to n.

Here-documents 

The << label redirector essentially forces the input to a command to be the shell’s standard input, which is read until there is a line that contains only label. The input in between is called a here-document. Here-documents aren’t very interesting when used from the command prompt. In fact, it’s the same as the normal use of standard input except for the label. We could use a here-document to simulate the mail facility. When you send a message to someone with the mail utility, you end the message with a dot (.). The body of the message is saved in a file, msgfile:

$ cat >> msgfile << .
> this is the text of
> our message.
> .

  bashbug script

MACHINE="i586"
OS="linux-gnu"
CC="gcc"
CFLAGS=" -DPROGRAM='bash' -DHOSTTYPE='i586' -DOSTYPE='linux-gnu' 
-DMACHTYPE='i586-pc-linux-gnu' -DSHELL -DHAVE_CONFIG_H
-I. 
-I. -I./lib -g -O2"
RELEASE="2.01"
PATCHLEVEL="0"
RELSTATUS="release"
MACHTYPE="i586-pc-linux-gnu"
TEMP=/tmp/bbug.$$
case "$RELSTATUS" in
alpha*|beta*)
BUGBASH=chet@po.cwru.edu ;;
*)
BUGBASH=bug-bash@prep.ai.mit.edu ;;
esac
BUGADDR="${1-$BUGBASH}"
UN=
if (uname) >/dev/null 2>&1; then
UN=`uname -a`
fi
cat > $TEMP <<EOF
From: ${USER}
To: ${BUGADDR}
Subject: [50 character or so descriptive subject here (for reference)]
Configuration Information [Automatically generated, do not change]:
Machine: $MACHINE
OS: $OS
Compiler: $CC
Compilation CFLAGS: $CFLAGS

name output: $UN
Machine Type: $MACHTYPE
bash Version: $RELEASE
Patch Level: $PATCHLEVEL
Release Status: $RELSTATUS
Description:
[Detailed description of the problem, suggestion, or complaint.]
Repeat-By:
[Describe the sequence of events that causes the problem
to occur.]
Fix:
[Description of how to fix the problem. If you don't know a
fix for the problem, don't include this section.]
EOF
vi $TEMP
mail $BUGADDR < $TEMP

  

File Descriptors

Task 7-2

You want to start a long job in the background (so that your terminal is freed up) and
save both standard output and standard error in a single log file. Write a script that
does this.

We’ll call this script start. The code is very terse:

"$@" > logfile 2>&1 &

  This line executes whatever command and parameters follow start. (The command cannot contain pipes or output redirectors.) It sends the command’s standard output to logfile.Then, the redirector 2>&1 says, “send standard error (file descriptor 2) to the same place as standard output (file descriptor 1).” Since standard output is redirected to 

logfile, standard error will go there too. The final & puts the job in the background so that you get your shell prompt back.

As a small variation on this theme, we can send both standard output and standard error into a pipe instead of a file: command 2>&1 | ... does this. (Make sure you understand why.) Here is a script that sends both standard output and standard error to the logfile (as above) and to the terminal:

"$@" 2>&1 | tee logfile &

  

These scripts have one shortcoming: you must remain logged in until the job completes. Although you can always type jobs (see Chapter 1) to check on progress, you can’t leave your terminal until the job finishes, unless you want to risk a breach of security.  We’ll see how to solve this problem in the next chapter.

 Before we leave this topic, we should just note that 1> is the same as >, and 0< is the same as <. If you understand this, then you probably know all you need to know about file descriptors.

String I/O

echo|printf|read

Option Function
-e Turns on the interpretation of backslash-escaped characters
-E Turns off the interpretation of backslash-escaped characters on systems where this mode is the default
-n Omits the final newline (same as the c escape sequence)

You may ask why this is any better than echo. The printf command has two parts, which is what makes it so powerful

printf format-string [arguments]

  

The first part is a string that describes the format specifications; this is best supplied as a string constant in quotes. The second part is an argument list, such as a list of strings or variable values that correspond to the format specifications. (The format is reused as necessary to use up all of the arguments. If the format requires more arguments than are supplied, the extra format specifications behave as if a zero value or null string, as appropriate, had been supplied). A format specification is preceded by a percent sign (%), and the specifier is one of the characters described below. Two of the main format specifiers are %s for strings and %d for decimal integers.

cor@debian:~/shell/mar9$ printf "%s %s
" hello world
hello world
cor@debian:~/shell/mar9$ printf "hello %s
" world
hello world
cor@debian:~/shell/mar9$ printf "|%10s|
" hello
|     hello|
cor@debian:~/shell/mar9$ printf "|%-10s|
" hello
|hello     |

  The allowed specifiers are shown in Table 7-4

Specifier Description
%c ASCII character (prints first character of corresponding argument)
%d Decimal integer
%i Same as %d
%e Floating-point format ([-]d.precisione[+-]dd) (see following text for meaning of precision)
%E Floating-point format ([-]d.precisionE[+-]dd)
%f Floating-point format ([-]ddd.precision)
%g %e or %f conversion, whichever is shorter, with trailing zeros removed
%G %E or %f conversion, whichever is shortest, with trailing zeros removed
%o Unsigned octal value
%s String
%u Unsigned decimal value    
%x Unsigned hexadecimal number; uses a-f for 10 to 15
%X Unsigned hexadecimal number; uses A-F for 10 to 15
%% Literal %

The precision modifier, used for decimal or floating-point values, controls the number of digits that appear in the result. For string values, it controls the maximum number of characters from the string that will be printed.

You can specify both the width and precision dynamically, via values in the printf argument list. You do this by specifying asterisks, instead of literal values.

cor@debian:~/shell/mar9$ myvar=42.123456
cor@debian:~/shell/mar9$ printf "|%*.*G|
" 5 6 $myvar
|42.1235|

cor@debian:~/shell/mar9$ printf "|%*.*G| " 5 5 $myvar
|42.123|
cor@debian:~/shell/mar9$ printf "|%*.*G| " 5 4 $myvar
|42.12|
cor@debian:~/shell/mar9$ printf "|%*.*G| " 5 3 $myvar
| 42.1|
cor@debian:~/shell/mar9$ printf "|%*.*G| " 4 6 $myvar
|42.1235|
cor@debian:~/shell/mar9$ printf "|%*.*G| " 3 6 $myvar
|42.1235|
cor@debian:~/shell/mar9$ printf "|%*.*G| " 2 6 $myvar
|42.1235|

In this example, the width is 5, the precision is 6, and the value to print comes from the value of myvar.

 Additional bash printf specifiers

Besides the standard specifiers just described, the bash shell (and other POSIX compliant shells) accepts two additional specifiers. These provide useful features at the expense of nonportability to versions of the printf command found in some other shells and in other places in UNIX:

%b

When used instead of %s, expands echo-style escape sequences in the argument string. For example:

cor@debian:~/shell/mar9$ printf "%s
" 'hello
world'
hello
world
cor@debian:~/shell/mar9$ printf "%b
" 'hello
world'
hello
world

  %q

When used instead of %s, prints the string argument in such a way that it can be used for shell input. For example:

cor@debian:~/shell/mar9$ printf "%q
" "greetings to the world"
greetings to the world

  read

The other half of the shell’s string I/O facilities is the read command, which allows you to read values into shell variables. The basic syntax is:

read var1 var2...

  

This statement takes a line from the standard input and breaks it down into words delimited by any of the characters in the value of the environment variable IFS (see Chapter 4; these are usually a space, a TAB, and NEWLINE). The words are assigned to variables var1, var2, etc. For example:

If there are more words than variables, then excess words are assigned to the last variable. If you omit the variables altogether, the entire line of input is assigned to the variable REPLY.

Reading user input

echo 'Select a directory:'
done=false
while [ $done = false ]; do
do=true
num=1
for direc in $DIR_STACK; do
echo $num) $direc
num=$((num+1))
done
echo -n 'directory? '
read REPLY
if [ $REPLY -lt $num ] && [ $REPLY -gt 0 ]; then
set - $DIR_STACK
#statements that manipulate the stack...
break
else
echo 'invalid selection.'
fi
done

  

Before leaving read, we should note that it has eight options: -a, -d, -e, -n, -p, -r, -t, and -s

The first of these options allows you to read values into an array. Each successive item read in is assigned to the given array starting at index 0. For example:

cor@debian:~/shell/mar9$ read -a people
alice duchess dodo
cor@debian:~/shell/mar9$ echo ${people[2]}
dodoalice

  

原文地址:https://www.cnblogs.com/winditsway/p/14500214.html