Pregunta

This script should accept a set of search terms and return a formatted URL to search google.

$ ./google_search.sh albert einstein
https://www.google.com/search?q=albert+einstein

It does that just fine, so I decided to add an option to search a specific site, or ignore that site, using a -s or -S flag.

$ ./google_search.sh -s wikipedia.org albert einstein
https://www.google.com/search?q=albert+einstein+site%3Awikipedia.org

This works the first time you run the script, but fails on every following attempt.

$ ./google_search.sh -s wikipedia.org albert einstein
https://www.google.com/search?q=albert+einstein
$ ./google_search.sh -s wikipedia.org albert einstein
https://www.google.com/search?q=albert+einstein

Opening a new Terminal window or restarting Terminal both clear this problem and allow one more attempt before failing.

The script:

#!/bin/bash

# original source of concatenate_args function by Tyilo:
# http://stackoverflow.com/questions/9354847/concatenate-inputs-in-bash-script
function concatenate_args
{
    string=""
    ignorenext=0
    for a in "$@" # Loop over arguments
    do
        if [[ "${a:0:1}" != "-" && $ignorenext = 0 ]] # Ignore flags (first character is -)
        then
            if [[ "$string" != "" ]]
            then
                string+="+" # Delimeter
            fi
            string+="$a"
        elif [[ $ignorenext = 1 ]]
        then
            ignorenext=0
        else
            ignorenext=1
        fi
    done
    echo "$string"
}

qry="$(concatenate_args "$@")"
glink="https://www.google.com/search?q="

site=""
while getopts :s:S: opt; do
    case $opt in
        s) site="+site%3A$OPTARG" ;; 
        S) site="+-site%3A$OPTARG" ;; 
    esac
done

url=$glink$qry$site

echo $url
# open -a Firefox $url

What needs to change to make this script more reliable?

¿Fue útil?

Solución

This is behaving like your are sourcing the script instead of executing it. If you use a dot and a space before the script, it causes the script to be executed line by line inside your current shell instead of creating a new shell. This allows environment variables that are changed inside the script to leak into your current shell's environment, which can make one run of the script not behave the same as the next.

In this case, it appears to be the use of getopts. getopts updates an environment variable each time it is called so it can keep track of which argument is being examined. The second time you source the script, it thinks that all the arguments have already been examined, so your argument ends up being ignored.

Otros consejos

Your script, simplified:

#!/bin/bash
glink="https://www.google.com/search?q="
site=""

# if you're "source"ing, uncomment the following:
# OPTIND=1

while getopts :s:S: opt; do
    case $opt in
        s) site="+site:$OPTARG" ;; 
        S) site="+-site:$OPTARG" ;; 
        ?) echo "invalid option: -$OPTARG" >&2 ;;
    esac
done
shift $((OPTIND - 1))
# the positional parameters are now clear of "-s" and "-S" options

qry=$(IFS="+"; echo "$*")
url=$glink$qry$site
echo "$url"
# open -a Firefox "$url"
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top