Aqui temos um livro livre e completo sobre Shell

Os sedentos do "saber livre" são muito benvindos.

Você está aqui: TWikiBar > TWikiBarTalk009
Controles: EDITAR ANEXAR MAIS MAIS ALTERACOES IMPRIMIR - Última Atualização: [25 Dec 2017 - V.13]

Pub Talk Part IX

This is a very new translation from Portuguese to English. Please contribute to the development of this site indicating errors and and/or suggesting corrections and materials for this person.

     - Okay, I know you will want to beer before you start, but I'm so anxious to show you what I did that I'm already asking to round up and then I'll show you.

     - Yo waiter, send two. His is no foam to not let this bad smell mustache ...

     - While the beer does not arrive let me remind you that you asked me to remake the listartist with formatted screen, in loop, so it only ends when you receive a pure <ENTER> on the name of artist. Possible error messages and questions should be given in the penultimate line of the screen using the routine sendmsg.func and question.func that just developed.

     - First I gave a shrunken in the sendmsg.func and question.func, which were as follows:

$ cat sendmsg.func # The function takes only one parameter # with the message that you want to display, # to not force the programmer to pass # the message in quotes, we'll use $* (all # parameters, remember?) and not $1. Msg="$*" TamMsg=${#Msg} Col=$(((TotCols - TamMsg) / 2)) # Centralizes message on row tput cup $LineMesg $Col read -n1 -p "$Msg "

$ cat question.func # The function takes 3 parameters in the following order: # $1 - Message to be given on the screen # $2 - Value to be accepted with default response # $3 - The other accepted value # Supposing that $1=Accept?, $2=y e $3=n, the row # then put the value in message "Accept? (Y/n)" Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" TamMsg=${#Msg} Col=$(((TotCols - TamMsg) / 2)) # Centralizes message on row tput cup $LineMesg $Col read -n1 -p "$Msg " SN [ ! $SN ] && SN=$2 # If empty puts default on SN SN=$(echo $SN | tr A-Z a-z) # The output of SN will be in lowercase tput cup $LineMesg $Col; tput el # Deletes the message screen

     - And now here's the big one:

$ cat listartista3 #!/bin/bash # Entered an artist, shows his musics # version 3

LineMesg=$((`tput lines` - 3)) # Line messages will be given to operator TotCols=$(tput cols) # Number of columns of screen to frame messages

clear echo " +-----------------------------------------+  | List All Songs of a Particular Artist |  | ---- --- ----- -- - ---------- ------ |  | |  | Enter the Artist: | +-----------------------------------------+" while true do tput cup 5 51; tput ech 31 # ech=Erase chars (31 characters to not erase vertical bar) read Name if [ ! "$Name" ] # $Is Name empty? then . question.func "Do you wish to finish?" y n [ $SN = n ] && continue break fi

fgrep -iq "^$Name~" musics || # fgrep not interpret ^ as regular expression { . sendmsg.func "There is no music of this artist" continue }

tput cup 7 29; echo '| |' LinAtual=8 IFS=" :" for ArtMus in $(cut -f2 -d^ musics) # Deletes album name do if echo "$ArtMus" | grep -iq "^$Name~" then tput cup $LinAtual 29 echo -n '| ' echo $ArtMus | cut -f2 -d~ tput cup $LinAtual 82 echo '|' let LinAtual++ if [ $LinAtual -eq $LineMesg ] then . sendmsg.func "Enter Something to Continue..." tput cup 7 0; tput ed # Erases the screen from row 7 tput cup 7 29; echo '| |' LinAtual=8 fi fi done tput cup $LinAtual 29; echo '| |' tput cup $((++LinAtual)) 29 read -n1 -p "+-----------Enter Something to New Query------------+" tput cup 7 0; tput ed # Erases the screen from row 7 done

     - Gosh, you got it all! But I liked the way you solved the problem and structured the program. It was more laborious but the presentation was very cool and you explored tput options. Let's test the result with an album Emerson, Lake & Palmer I have registered.

              |  List All Songs of a Particular Artist       |
              |  ---- --- ----- -- - ---------- ------       |
              |                                              |
              |  Enter the Artist: Emerson, Lake & Palmer    |
              |                                              |
              |  Jerusalem                                   |
              |  Toccata                                     |
              |  Still ... You Turn Me On                    |
              |  Benny The Bouncer                           |
              |  Karn Evil 9                                 |
              |                                              |
              +---------Enter Something to New Query---------+

Improving writing

    - Whew! Now you know all about reading, but about writing is just beginning. I know you will ask me:
    - Well, is not with the echo command and with the output redirections you write?

It's with these commands you write 90% of the necessary things, but if you need something to write formatted they will give you a lot of work. To format the output now we will see a very interesting statement and it's very fast implementation, because, like the echo, it's an intrinsic command (builtin) of Shell - it's the printf - it's syntax is as follows:

    printf format [argument...]

format - it's a chain that contains three types of object:

  1. simple character;
  2. characters for format specification;
  3. escape sequence in standard C language.
Argument - it's the chain to be printed under the control of format.

Each of the characters used for specifying format is preceded by the character %, then there follows the specification format according to the table:

Table of Formatting Characters printf
%  Prints a %. No conversion exists  
  Letter     The expression will be printed as:
c  simple character  
d  Number in the decimal system  
e  Exponential scientific notation  
f  Number with decimal point (float)  
g The lower among the formats %e and %f with suppression of no significant zeros.
o  Number in octal system  
s  Character chain  
x  Number in hexadecimal system  

The sequences of the C language standard escape are always preceded by a backslash (\) and recognized by the printf command are:

Sequences Escape printf
t   Advances to the next tab stop  
  Sequence     Effect  
a   The beep sounds  
b   Back one position (backspace)  
f   Jump to the next logical page (form feed)  
n   Jumps to the beginning of the next row (line feed)  
r   Back to the beginning of current line (carriage return)  

Not end here! It has a lot more going about instruction, but as it is very full of details and therefore boring to explain, and even worse to read or study, let's jump right to the examples with your comments, I'm not here to bother anyone.

$ printf "%c" "1 character" 1$ Wrong! Listed only 1 character and not jumped row to the end $ printf "%c\n" "1 character" 1 Jumped row but not yet listed the full chain $ printf "%c character\n" 1 1 character This is the correct way the %c received the 1 $ a=2 $ printf "%c character\n" $a 2 character The %c received the value of the $a variable $ printf "%10c character\n" $a          2 character $ printf "%10c\n" $a character          2 c

Note that the last two examples, because of %c, was only listed one character of each chain. The 10 ahead of c no means 10 characters. A number following the percent sign (%) means size that the chain will have after running the command.

And take for example:

$ printf "%d\n" 32 32 $ printf "%10d\n" 32 32 Fills with white left and with no zeros $ printf "%04d\n" 32 0032 04 after % means 4 digits with leading zeros $ printf "%e\n" $(echo "scale=2 ; 100/6" | bc) 1.666000e+01 The default of %e it's 6 decimal $ printf "%.2e\n" `echo "scale=2 ; 100/6" | bc` 1.67e+01 The .2 specifies two decimal $ printf "%f\n" 32.3 32.300000 The default of %f it's 6 decimal $ printf "%.2f\n" 32.3 32.30 The .2 specifies two decimal $ printf "%.3f\n" `echo "scale=2 ; 100/6" | bc` 33.330 The bc returned 2 decimals. The printf put 0 on the right $ printf "%o\n" 10 12 Converted the 10 to octal $ printf "%03o\n" 27 033 So the conversion becomes more like octal, right? $ printf "%s\n" Peteleca Peteleca $ printf "%15s\n" Peteleca Peteleca Peteleca with 15 characters filled with whites $ printf "%-15sNeves\n" Peteleca Peteleca Neves The minus (-) filled the right with whites $ printf "%.3s\n" Peteleca Pet 3 truncates the first 3 $ printf "%10.3sa\n" Peteleca Peta Pet with 10 characters concatenated with (after the s) $ printf "EXAMPLE %x\n" 45232 EXAMPLE b0b0 Turned to hexa but the zeros don't combine $ printf "EXEMPLO %X\n" 45232 EXAMPLE B0B0? Thus disguised better (note the X caps) $ printf "%X %XL%X\n" 49354 192 10 C0CA? C0LA?

The last example isn't marketing and it's very complete, I will comment on it step-by-step:

  1. he first %X converted in hexadecimal 49354 resulting C0CA (read "cê", "zero", "cê" and "a");
  2. Then came a blank space followed by another %XL. The %X converted 192 resulting in C0 it with L did C0L;
  3. And finally the last %X turned 10 in A.

As you can see, the instruction printf it's fairly complete and complex (even though the echo solves almost everything).

I believe I did right when I decided to explain printf using examples, because I wouldn't know how to enumerate so many little rules without make for tedious reading.

Main Shell Variables

Bash has several variables that serve to give information about the environment or change it. Their number is very large and does not intend to show all but a small part that can help you in developing scripts. So here goes the main ones:

Main Bash Variables
TMOUT If it has a value greater than zero, this value is taken as the default timeout read command. In the prompt, this value is interpreted as the waiting time for an action before the session expires. Supposing that the variable contains 30, the Shell will logout after 30 seconds without any prompt action.
      Variable Content
CDPATH Contains the paths to be searched to try to find a specified directory. Although this variable is little known, their use should be encouraged by saving a lot of work, especially in installations with directory structure with enough levels.
HISTSIZE Limits the number of instructions that fit within the command history file (normally .bash_history but effectively it's what is stored in the variable $=HISTFILE=). Your default value is 500.  
HOSTNAME The host name of the current (which may also be obtained from the uname -n command).
LANG Used to determine the language spoken in the country (more specifically locale category).
LINENO The row number of the script or function being executed, their main use it is to give error messages along with the variables $0 (program name) and $FUNCNAME (name of executing function)
LOGNAME Stores the user's login name.
MAILCHECK Specifies, in seconds, how often the Shell will check for mail in the files specified by variables $MAILPATH or $MAIL. The default time is 60 seconds. Once this time expires, the Shell will make this check before displaying the next primary prompt (defined in $PS1). If that it's valueless or less than or equal to zero, checking for new mail will not be effected.
PATH Paths that will be searched to try to find a specified file. How each script is a file, if you use the current directory (.) in your $PATH variable, you'll not need to use the ./scrp to scrp runs. Just do scrp. This is the way I proceed here in Pub.
PIPESTATUS It's a variable of type vector (array) containing a list of return code values pipeline the last run, that is, array one that shelters each $? each statement last pipeline.
PROMPT_COMMAND If this variable receives a direction, every time you give a <ENTER> direct to the main prompt ($PS1), this command will run. It's useful when you're repeating much a given instruction.
PS1 It is the main prompt. In "Pub Talk" we use their defaults: $ for common user and # for root, but most often it's customized. A curiosity is that exists until competition of who the program $PS1 more creatively . (click here to see in Google)
PS2 Also called continuation prompt, is one sign of greater (>) that appears after a <ENTER> without the command has been closed.
PWD Contains the full path ($PATH) the current directory. Has the same effect of the pwd command.
RANDOM Each time this variable is accessed, it returns an integral number, which is a random between 0 and 32767.
REPLY Use this variable to retrieve the last field read, if it has no variable associated.
SECONDS This variable contains the number of seconds that the current Shell is standing. Use it only to ignore a user what we call the operating system, but requires frequent boots. smile


$ echo $CDPATH .:..:~:/usr/local $ pwd /home/jneves/LM $ cd bin $ pwd /usr/local/bin

As /usr/local was in my variable $CDPATH, and there wasn't bin directory in any of it's predecessors (., .. and ~), the cd was run for /usr/local/bin

  • LANG

$ date Thu Apr 14 11:54:13 BRT 2005 $ LANG=pt_BR date Qui Abr 14 11:55:14 BRT 2005

With the specifying the variable LANG=pt_BR (Portuguese from Brazil), the date passed to be informed in the Brazilian standard. It's interesting to note that it wasn't used semicolon (;) to separate the assignment LANG of date command.


$ who jneves pts/0 Apr 11 16:26 ( jneves pts/1 Apr 12 12:04 ( $ who | grep ^botelho $ echo ${PIPESTATUS[*]} 0 1

In this example we showed that the user botelho wasn't "logged" then we executed a pipeline that were looking for it. Uses the notation [*] in a array to list all it's elements, and thus we saw that the first statement (who) was successful (return code 0) and the next (grep) not (return code 1).


To generate randomly an integer between 0 and 100, do:

$ echo $((RANDOM%101)) 73

That is, we took the rest of the division by 101 of the random number generated, because the remainder of dividing any number by 101 varies from 0 and 100.


$ read -p "Digite S ou N: " Digite S ou N: N $ echo $REPLY N

I am the time that memory was a valuable asset that was so expensive. So to get a S or N I don't usually allocate a special space and therefore, I caught what was typed in the variable $REPLY.

Expansion of parameters

Well, a lot of what we have seen so far are external to Shell commands. They help us facilitate the visualization, maintenance and debugging code, but are not as efficient as the intrinsic (built-ins). When our problem is performance, we should give preference to the use of intrinsic and from now on I will show you some techniques for your program step on the accelerator.

In the following examples and table, we will see a number of buildings expansion calls (or replacement) of parameters (Parameter Expansion), which replace instructions as the cut, the expr, the tr, the sed and others more agile.

Expansion of parameters
  ${chain~~}   Swaps the box every letter chain (from the bash 4.0
  Expression   Expected Result
  ${var:-default}   If var hasn't value, the result of the expression is default
  ${#chain}   Size of $chain
  ${chain:position}   Extracts a subchain $chain from position. Origin zero
  ${chain:posicion:size}   Extracts a subchain $chain from position with size equal to size. Origin zero
  ${chain#expr}   Cuts the lower occurrence of $chain to the left of expression expr
  ${chain##expr}   Cuts the most occurrence of $chain to the left of expression expr
  ${chain%expr}   Cuts the lower occurrence of $chain to the right of expression expr
  ${chain%%expr}   Cuts the most occurrence of $chain to the right of expression expr
  ${chain/subcad1/subcad2}   Exchange in $chain the first occurrence of subcad1 by subcad2
  ${chain//subcad1/subcad2}   Exchange in $chain all occurrences of subcad1 by subcad2
  ${chain/#subcad1/subcad2}   If subcad1 combines with beginning of $chain, then it is replaced by subcad2
  ${chain/%subcad1/subcad2}   If subcad1 combines with the end of $chain, then it is replaced by subcad2
  ${chain^}   Puts the first letter of chain in uppercase (from the bash 4.0)
  ${chain^^}   Puts all letters of chain in uppercase (from the bash 4.0)
  ${chain,}   Puts the first letter of chain in lowercase (from the bash 4.0)
  ${chain,,}   Puts all letters of chain in lowercase (from the bash 4.0)
  ${chain~}   Swaps the box every first letter of words chain (from the bash 4.0)

  • If into a question the S is offered as default value and the output goes to the variable $SN, after reading the value we can do:


Thus if the operator has a simple <ENTER> to confirm that accepted the default value after executing this instruction, the variable will have the value S, otherwise, will have the value entered.

  • To know the size of a chain:

$ chain=0123 $ echo ${#chain} 4

  • To extract a chain from one position to the end do:

$ chain=abcdef $ echo ${chain:1} bcdef

Notice that the origin is zero and not one.

  • In the same variable = $ chain = of the above example, to extract 3 characters from the 2nd position

$ echo ${chain:2:3} cde

Notice again that the origin is zero and not one.

  • We can also extract of the end to the beginning

$ GoodTeam=Flamengo $ echo ${GoodTeam: -5} mengo $ echo ${GoodTeam:(-5)} mengo

The white space or parentheses are required for the minus sign (-) not paste in the colon (:), which if it occurred, would be similar to expansion we saw above and replacing an empty or null variable with a default value (default), in other words the famous ${var:-default}.

  • To suppress everything to the left of the first occurrence of a chain, do:

$ chain="Talk Pub" $ echo ${chain#*' '} Pub $ echo "Talk "${chain#*' '} Pub Talk

In this instance was suppressed to the left everything corresponded with the lowest occurrence of the expression *' ', that is, everything until the first space in blank.

These examples could also be written without us protect the space of Shell interpretation (but I prefer to protect it for readability of the code), see:

$ echo ${chain#* } Pub $ echo "Talk "${chain#* } Pub Talk

Note that in building of expr the use of metacharacters is allowed.

  • Using the same variable value $chain note how we would to have only Pub:

$ echo ${chain##*' '} Pub $ echo "Let's go 'drink' in "${chain##*' '} Let's go 'drink' in the Pub

This time, we suppress to the left of the chain the higher occurrence of the expression expr. As in the previous case, the use of metacharacters is allowed.

Another more useful example: do not appear for the full path (path) of your program (which as we know is contained in the variable $0) in an error message, start your text as follows:

    echo Use: ${0##*/} text of the error message

In this example would be suppressed to the left everything until the last bar (/) the path (path) thus leaving only the name of the program.

  • The use of percentage (%) is like looking the tic-tac-toe (#) in the mirror, that is, are symmetrical. So let's look at an example to prove it:

$ echo $chain Pub Talk $ echo ${chain%' '*} Talk $ echo ${chain%%' '*} Talk

  • To replace the first occurrence of a subchain in a chain for another:

$ echo $chain Pub Talk $ echo ${chain/of/no} Pub Talk $ echo ${chain/of /} Pub Talk

In this case pay attention when using metacharacters, they are greedy! They always will combine with greater possibility. See the following example where the intent was to exchange Pub Talk by Pub Conversation:

$ echo $chain Pub Talk $ echo ${chain/*the/Conversation} Conversapub

The idea was to catch everything the first the, but what was exchanged was everything until the last the. This could be solved in several ways, here are some:

$ echo ${chain/*po/Conversation} Pub Conversation $ echo ${chain/????/Conversation} Pub Conversation

  • Replacing all occurrences of a subchain with another. When we do::

$ echo ${chain//a/o} Pub Tolk

We exchanged all letters a from o. See now a script to remove white spaces from file names.

$ cat Removewhite.sh #!/bin/bash # Rename files with white space #+ on the name, replacing them by underscores (_). Error=0 for Arq in *' '* do [ -f ${Arq// /_} ] && { echo $Arq not been renamed Error=1 continue } mv "$Arq" "${Arq// /_}" done 2> /dev/null # If there is no whites file with the command for gives error exit $Error

  • Replacing a subchain at the beginning or end of a variable. To change the beginning we do:

$ echo $Bird quero quero $ echo "As the man from southern Brazil says - "${Bird/#want/not} As the man from southern Brazil says - not want

To change the end we do:

$ echo "As the man from northern Brazil says - "${Bird/%want/not} As the man from northern Brazil says - not want

These expansions were introduced from the Bash 4.0 and change the letter case of the text being expanded. When we use caret (^), the expansion is made to uppercase when using comma (,), the expansion is made for lowercase and when we use tilde (~) the expansion changes the case of the letters.

$ Name="botelho" $ echo ${Name^} Botelho $ echo ${Nome^^} BOTELHO $ Name="botelho carvalho" $ echo ${Name^} Botelho carvalho $ echo ${Name~} # Capitalizing $Name Botelho Carvalho $ Thing="AAAbbb cccDDD" $ echo ${Thing~} aAAbbb CccDDD $ echo ${Thing~~} aaaBBB CCCddd

A fragment of script that can make your life easier:

read -p "Do you wish to continue? (y/n)? "
[[ ${REPLY^} == N ]] && exit

This form avoids we test whether the answer given was a N (uppercase) or an n (lowercase).

In rWindows, beyond the viruses and instability, are also common filenames with a blank space and almost all uppercase. We have already seen an example of how to replace white spaces by underscores (_), next we will see how to pass them to lowercase (if you receive many files from that thing, it's best to create a script that the combination of these two).

$ cat changecase.sh #!/bin/bash # If the file name has at least one #+ capital letter, return it to lowercase

for Arq in *[A-Z]* # Files with at least 1 lowercase do if [ -f "${Arq,,}" ] # Arq lowercase already exists? then echo ${Arq,,} already exists else mv "$Arq" "${Arq,,}" fi done

That's enough, the talk today was very boring because it was a lot of memorization, but the main thing is you have understood what I told you, and when you need it again, see these napkins in which I scribbled these tips and then save them for future reference. But back to what matters: it's time to take another and watch the football game. Next I'll give you something easy and will only charge the following: take routine question.func, (which we talked about in the beginning of our conversation today) and optimize it to the variable $SN receive the default value for parameter expansion, as we have seen.

     - Waiter, don't forget me and fills up my cup.

Any doubt or lack of companionship for a beer or even to speak ill of politicians just send an email to of me.



-- PauloSantana - 25 Dec 2017

Licença Creative Commons - Atribuição e Não Comercial (CC) 2018 Pelos Frequentadores do Bar do Júlio Neves.
Todo o conteúdo desta página pode ser utilizado segundo os termos da Creative Commons License: Atribuição-UsoNãoComercial-PermanênciaDaLicença.