how to remove the return char in an output
echo -n hallo >> test
Important bug in grep---unexpected termination of grep -c (both Linux and Mac)
When grep -c outputs 0 for not finding any matches, the output CANNOT be stored in any variables and it will stop the whole bash file.
To get around it, use if statement to detect whether there are matches and assign a zero value to the result.
#Hope this bug will be fixed in future
Array of strings
10.2.1. Creating arrays
An array is a variable containing multiple values. Any variable may be used as an array. There is no maximum limit to the size of an array, nor any requirement that member variables be indexed or assigned contiguously. Arrays are zero-based: the first element is indexed with the number 0.
Indirect declaration is done using the following syntax to declare a variable:
ARRAY[INDEXNR]=value
The INDEXNR is treated as an arithmetic expression that must evaluate to a positive number.
Explicit declaration of an array is done using the declare built-in:
declare -a ARRAYNAME
A declaration with an index number will also be accepted, but the index number will be ignored. Attributes to the array may be specified using the declare and readonly built-ins. Attributes apply to all variables in the array; you can't have mixed arrays.
Array variables may also be created using compound assignments in this format:
ARRAY=(value1 value2 ... valueN)
Each value is then in the form of [indexnumber=]string. The index number is optional. If it is supplied, that index is assigned to it; otherwise the index of the element assigned is the number of the last index that was assigned, plus one. This format is accepted by declare as well. If no index numbers are supplied, indexing starts at zero.
Adding missing or extra members in an array is done using the syntax:
ARRAYNAME[indexnumber]=value
Remember that the read built-in provides the -a option, which allows for reading and assigning values for member variables of an array.
10.2.2. Dereferencing the variables in an array
In order to refer to the content of an item in an array, use curly braces. This is necessary, as you can see from the following example, to bypass the shell interpretation of expansion operators. If the index number is @ or *, all members of an array are referenced.
[bob in ~] ARRAY=(one two three)[bob in ~] echo ${ARRAY[*]}one two three[bob in ~] echo $ARRAY[*]one[*][bob in ~] echo ${ARRAY[2]}three[bob in ~] ARRAY[3]=four[bob in ~] echo ${ARRAY[*]}one two three four |
Referring to the content of a member variable of an array without providing an index number is the same as referring to the content of the first element, the one referenced with index number zero.
10.2.3. Deleting array variables
The unset built-in is used to destroy arrays or member variables of an array:
[bob in ~] unset ARRAY[1][bob in ~] echo ${ARRAY[*]}one three four[bob in ~] unset ARRAY[bob in ~] echo ${ARRAY[*]}<--no output--> |
10.2.4. Examples of arrays
Practical examples of the usage of arrays are hard to find. You will find plenty of scripts that don't really do anything on your system but that do use arrays to calculate mathematical series, for instance. And that would be one of the more interesting examples...most scripts just show what you can do with an array in an oversimplified and theoretical way.
The reason for this dullness is that arrays are rather complex structures. You will find that most practical examples for which arrays could be used are already implemented on your system using arrays, however on a lower level, in the C programming language in which most UNIX commands are written. A good example is the Bash history built-in command. Those readers who are interested might check the built-ins directory in the Bash source tree and take a look at fc.def, which is processed when compiling the built-ins.
Another reason good examples are hard to find is that not all shells support arrays, so they break compatibility.
After long days of searching, I finally found this example operating at an Internet provider. It distributes Apache web server configuration files onto hosts in a web farm:
#!/bin/bashif [ $(whoami) != 'root' ]; then echo "Must be root to run $0" exit 1;fiif [ -z $1 ]; then echo "Usage: $0 </path/to/httpd.conf>" exit 1fihttpd_conf_new=$1httpd_conf_path="/usr/local/apache/conf"login=htuserfarm_hosts=(web03 web04 web05 web06 web07)for i in ${farm_hosts[@]}; do su $login -c "scp $httpd_conf_new ${i}:${httpd_conf_path}" su $login -c "ssh $i sudo /usr/local/apache/bin/apachectl graceful"doneexit 0 |
First two tests are performed to check whether the correct user is running the script with the correct arguments. The names of the hosts that need to be configured are listed in the array farm_hosts. Then all these hosts are provided with the Apache configuration file, after which the daemon is restarted. Note the use of commands from the Secure Shell suite, encrypting the connections to remote hosts.
Thanks, Eugene and colleague, for this contribution.
Dan Richter contributed the following example. This is the problem he was confronted with:
"...In my company, we have demos on our web site, and every week someone has to test all of them. So I have a cron job that fills an array with the possible candidates, uses date +%W to find the week of the year, and does a modulo operation to find the correct index. The lucky person gets notified by e-mail."
And this was his way of solving it:
#!/bin/bash# This is get-tester-address.sh ## First, we test whether bash supports arrays.# (Support for arrays was only added recently.)#whotest[0]='test' || (echo 'Failure: arrays not supported in this version ofbash.' && exit 2) ## Our list of candidates. (Feel free to add or# remove candidates.)#wholist=( 'Bob Smith <bob@example.com>' 'Jane L. Williams <jane@example.com>' 'Eric S. Raymond <esr@example.com>' 'Larry Wall <wall@example.com>' 'Linus Torvalds <linus@example.com>' )## Count the number of possible testers.# (Loop until we find an empty string.)#count=0while [ "x${wholist[count]}" != "x" ]do count=$(( $count + 1 ))done ## Now we calculate whose turn it is.#week=`date '+%W'` # The week of the year (0..53).week=${week#0} # Remove possible leading zero. let "index = $week % $count" # week modulo count = the lucky personemail=${wholist[index]} # Get the lucky person's e-mail address. echo $email # Output the person's e-mail address. |
This script is then used in other scripts, such as this one, which uses a here document:
email=`get-tester-address.sh` # Find who to e-mail.hostname=`hostname` # This machine's name. ## Send e-mail to the right person.#mail $email -s '[Demo Testing]' <<EOFThe lucky tester this week is: $email Reminder: the list of demos is here: http://web.example.com:8080/DemoSites (This e-mail was generated by $0 on ${hostname}.)EOF
If you're used to a "standard" *NIX shell you may not be familiar with bash's array feature. Although not as powerful as similar constructs in the P languages (Perl, Python, and PHP) and others, they are often quite useful.
Bash arrays have numbered indexes only, but they are sparse, ie you don't have to define all the indexes. An entire array can be assigned by enclosing the array items in parenthesis:
arr=(Hello World) Individual items can be assigned with the familiar array syntax (unless you're used to Basic or Fortran):
arr[0]=Hello arr[1]=World But it gets a bit ugly when you want to refer to an array item:
echo ${arr[0]} ${arr[1]} To quote from the man page:
The braces are required to avoid conflicts with pathname expansion.
In addition the following funky constructs are available:
${arr[*]} # All of the items in the array ${!arr[*]} # All of the indexes in the array ${#arr[*]} # Number of items in the array ${#arr[0]} # Length of item zero The ${!arr[*]} is a relatively new addition to bash, it was not part of the original array implementation.
The following example shows some simple array usage (note the "[index]=value" assignment to assign a specific index):
#!/bin/basharray=(one two three four [5]=five)echo "Array size: ${#array[*]}"echo "Array items:"for item in ${array[*]}doprintf " %s\n" $itemdoneecho "Array indexes:"for index in ${!array[*]}doprintf " %d\n" $indexdoneecho "Array items and indexes:"for index in ${!array[*]}doprintf "%4d: %s\n" $index ${array[$index]}done Running it produces the following output:
Array size: 5Array items: one two three four fiveArray indexes: 0 1 2 3 5Array items and indexes: 0: one 1: two 2: three 3: four 5: five
Note that the "@" sign can be used instead of the "*" in constructs such as${arr[*]}, the result is the same except when expanding to the items of the array within a quoted string. In this case the behavior is the same as when expanding "$*" and "$@" within quoted strings: "${arr[*]}" returns all the items as a single word, whereas "${arr[@]}" returns each item as a separate word.
The following example shows how unquoted, quoted "*", and quoted "@" affect the expansion (particularly important when the array items themselves contain spaces):
#!/bin/basharray=("first item" "second item" "third" "item")echo "Number of items in original array: ${#array[*]}"for ix in ${!array[*]}doprintf " %s\n" "${array[$ix]}"doneechoarr=(${array[*]})echo "After unquoted expansion: ${#arr[*]}"for ix in ${!arr[*]}doprintf " %s\n" "${arr[$ix]}"doneechoarr=("${array[*]}")echo "After * quoted expansion: ${#arr[*]}"for ix in ${!arr[*]}doprintf " %s\n" "${arr[$ix]}"doneechoarr=("${array[@]}")echo "After @ quoted expansion: ${#arr[*]}"for ix in ${!arr[*]}doprintf " %s\n" "${arr[$ix]}"done When run it outputs:
Number of items in original array: 4 first item second item third itemAfter unquoted expansion: 6 first item second item third itemAfter * quoted expansion: 1 first item second item third itemAfter @ quoted expansion: 4 first item second item third item |
comparison operators
A binary comparison operator compares two variables or quantities. Note that integer and string comparison use a different set of operators.
- -eq
- is equal toif [ "$a" -eq "$b" ]
- -ne
- is not equal toif [ "$a" -ne "$b" ]
- -gt
- is greater thanif [ "$a" -gt "$b" ]
- -ge
- is greater than or equal toif [ "$a" -ge "$b" ]
- -lt
- is less thanif [ "$a" -lt "$b" ]
- -le
- is less than or equal toif [ "$a" -le "$b" ]
- <
- is less than (within double parentheses)(("$a" < "$b"))
- <=
- is less than or equal to (within double parentheses)(("$a" <= "$b"))
- >
- is greater than (within double parentheses)(("$a" > "$b"))
- >=
- is greater than or equal to (within double parentheses)(("$a" >= "$b"))
- =
-
is equal toif [ "$a" = "$b" ]Note the whitespace framing the =.if [ "$a"="$b" ] is not equivalent to the above.
- ==
- is equal toif [ "$a" == "$b" ]This is a synonym for =.The == comparison operator behaves differently within a double-brackets test than within single brackets.
[[ $a == z* ]] # True if $a starts with an "z" (pattern matching).[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).[ $a == z* ] # File globbing and word splitting take place.[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).# Thanks, Stéphane Chazelas
- !=
- is not equal toif [ "$a" != "$b" ]This operator uses pattern matching within a [[ ... ]] construct.
- <
- is less than, in ASCII alphabetical orderif [[ "$a" < "$b" ]]if [ "$a" \< "$b" ]Note that the "<" needs to be escaped within a [ ] construct.
- >
- is greater than, in ASCII alphabetical orderif [[ "$a" > "$b" ]]if [ "$a" \> "$b" ]Note that the ">" needs to be escaped within a [ ] construct.See Example 27-11 for an application of this comparison operator.
- -z
- string is null, that is, has zero length
String='' # Zero-length ("null") string variable.if [ -z "$String" ]then echo "\$String is null."else echo "\$String is NOT null."fi # $String is null.
- -n
- string is not null.The -n test requires that the string be quoted within the test brackets. Using an unquoted string with ! -z, or even just the unquoted string alone within test brackets (see Example 7-6) normally works, however, this is an unsafe practice. Always quote a tested string. [1]
Example 7-5. Arithmetic and string comparisons
#!/bin/basha=4b=5# Here "a" and "b" can be treated either as integers or strings.# There is some blurring between the arithmetic and string comparisons,#+ since Bash variables are not strongly typed.# Bash permits integer operations and comparisons on variables#+ whose value consists of all-integer characters.# Caution advised, however.echoif [ "$a" -ne "$b" ]then echo "$a is not equal to $b" echo "(arithmetic comparison)"fiechoif [ "$a" != "$b" ]then echo "$a is not equal to $b." echo "(string comparison)" # "4" != "5" # ASCII 52 != ASCII 53fi# In this particular instance, both "-ne" and "!=" work.echoexit 0 |
Example 7-6. Testing whether a string is null
#!/bin/bash# str-test.sh: Testing null strings and unquoted strings,#+ but not strings and sealing wax, not to mention cabbages and kings . . .# Using if [ ... ]# If a string has not been initialized, it has no defined value.# This state is called "null" (not the same as zero!).if [ -n $string1 ] # string1 has not been declared or initialized.then echo "String \"string1\" is not null."else echo "String \"string1\" is null."fi # Wrong result.# Shows $string1 as not null, although it was not initialized.echo# Let's try it again.if [ -n "$string1" ] # This time, $string1 is quoted.then echo "String \"string1\" is not null."else echo "String \"string1\" is null."fi # Quote strings within test brackets!echoif [ $string1 ] # This time, $string1 stands naked.then echo "String \"string1\" is not null."else echo "String \"string1\" is null."fi # This works fine.# The [ ... ] test operator alone detects whether the string is null.# However it is good practice to quote it (if [ "$string1" ]).## As Stephane Chazelas points out,# if [ $string1 ] has one argument, "]"# if [ "$string1" ] has two arguments, the empty "$string1" and "]" echostring1=initializedif [ $string1 ] # Again, $string1 stands unquoted.then echo "String \"string1\" is not null."else echo "String \"string1\" is null."fi # Again, gives correct result.# Still, it is better to quote it ("$string1"), because . . .string1="a = b"if [ $string1 ] # Again, $string1 stands unquoted.then echo "String \"string1\" is not null."else echo "String \"string1\" is null."fi # Not quoting "$string1" now gives wrong result!exit 0 # Thank you, also, Florian Wisser, for the "heads-up". |
Example 7-7. zmore
#!/bin/bash# zmore# View gzipped files with 'more' filter.E_NOARGS=85E_NOTFOUND=86E_NOTGZIP=87if [ $# -eq 0 ] # same effect as: if [ -z "$1" ]# $1 can exist, but be empty: zmore "" arg2 arg3then echo "Usage: `basename $0` filename" >&2 # Error message to stderr. exit $E_NOARGS # Returns 85 as exit status of script (error code).fi filename=$1if [ ! -f "$filename" ] # Quoting $filename allows for possible spaces.then echo "File $filename not found!" >&2 # Error message to stderr. exit $E_NOTFOUNDfi if [ ${filename##*.} != "gz" ]# Using bracket in variable substitution.then echo "File $1 is not a gzipped file!" exit $E_NOTGZIPfi zcat $1 | more# Uses the 'more' filter.# May substitute 'less' if desired.exit $? # Script returns exit status of pipe.# Actually "exit $?" is unnecessary, as the script will, in any case,#+ return the exit status of the last command executed. |
- -a
- logical andexp1 -a exp2 returns true if both exp1 and exp2 are true.
- -o
- logical orexp1 -o exp2 returns true if either exp1 or exp2 is true.
These are similar to the Bash comparison operators && and ||, used within double brackets.
[[ condition1 && condition2 ]] |
The -o and -a operators work with the test command or occur within single test brackets.
if [ "$expr1" -a "$expr2" ]then echo "Both expr1 and expr2 are true."else echo "Either expr1 or expr2 is false."fi |
But, as rihad points out:
|
No comments:
Post a Comment