1

I have couple of files needed to be parsed here, called parse.sh. I have to enable optional arguments for it with -l for line, -f for field. So to run the program would be ./parse.sh -l 5 -f 14 foo. Without -l or -f arguments, I want the program to default parse all lines and all fields. If -l is specified, I want it to parse just that line of foo, and further if -f is specified too, I want it to parse just that field. I see getopts usually work like this:

while getopts "l:f:" opts; do
    case $opts in
        l) #code to parse that line;;
        f) #code to parse that field;;
    case
done

BUT this is not what I need, because I want -l and -f work together sometimes. I am thinking maybe I should do getopts to parse all options into array, then write code based on parsing that array? Any better choices?

This is my code:

while getopts "l:f:" opt;
do
    options=${opt}${options}
    case $opt in
            l) lineNumber=$OPTARG ;;
            f) fieldNumber=$OPTARG ;;
    esac
done

case $options in
    f) echo "Parse field $fieldNumber of each line" ;;
    l) echo "Parse all fields of line number $lineNumber" ;;
    lf | fl) echo "Parse field $fieldNumber of line $lineNumber" ;;
    *) echo "Parse all fields of all lines" ;;
esac
4

3 回答 3

2
#!/bin/bash

parse()
{
        local lines=$1
        local fields=$2
        local file=$3

        # logic goes here
        echo "parsing line(s) ${lines} and field(s) ${fields} of file ${file}"
}

lines=all
fields=all

while getopts "l:f:" o; do
        case $o in
                l) lines=${OPTARG}  ;;
                f) fields=${OPTARG} ;;
        esac
done
shift $((OPTIND-1))

for file; do
        parse "${lines}" "${fields}" "${file}"
done

示例运行:

$ ./t.sh foo.txt bar.txt
parsing line(s) all and field(s) all of file foo.txt
parsing line(s) all and field(s) all of file bar.txt

$ ./t.sh -l 10 foo.txt bar.txt
parsing line(s) 10 and field(s) all of file foo.txt
parsing line(s) 10 and field(s) all of file bar.txt

$ ./t.sh -l 10 -f 5 foo.txt bar.txt
parsing line(s) 10 and field(s) 5 of file foo.txt
parsing line(s) 10 and field(s) 5 of file bar.txt

$ ./t.sh -f 5 foo.txt bar.txt
parsing line(s) all and field(s) 5 of file foo.txt
parsing line(s) all and field(s) 5 of file bar.txt
于 2013-09-06T18:33:27.870 回答
1
#!/bin/bash

while getopts "l:f:" opts; do
    case $opts in
    l)
        lOn=1
        ;;
    f)
        fOn=1
        ;;
    esac
done

if [[ -n $lOn && -n $fOn ]]; then
    echo 'both l and f'
elif [[ -n $lOn ]]; then
    echo 'just l'
elif [[ -n $fOn ]]; then
    echo 'just f'
else
    echo 'nothing'
fi

当您想要检查其他变量或执行更复杂的事情时,如果语句为您提供了更大的灵活性。除非sh您更改[[ ]][ ].

于 2013-09-06T18:32:38.893 回答
1

我做了一个概念脚本。请试试。

#!/bin/bash

PARSE_SPECIFIC_LINE=0
PARSE_SPECIFIC_FIELD=0

shopt -s extglob

while getopts "l:f:" opts; do
    case $opts in
    l)
        if [[ $OPTARG != +([[:digit:]]) || OPTARG -lt 1 ]]; then
            echo "Invalid argument to -l: $OPTARG"
            exit 1
        fi
        PARSE_SPECIFIC_LINE=$OPTARG
        ;;
    f)
        if [[ $OPTARG != +([[:digit:]]) || OPTARG -lt 1 ]]; then
            echo "Invalid argument to -f: $OPTARG"
            exit 1
        fi
        PARSE_SPECIFIC_FIELD=$OPTARG
        ;;
    esac
done

FILES=("${@:OPTIND}")

function parse_line {
    local LINE=$1
    if [[ -n $LINE ]]; then
        if [[ PARSE_SPECIFIC_FIELD -gt 0 ]]; then
            read -ra FIELDS <<< "$LINE"
            echo "${FIELDS[PARSE_SPECIFIC_FIELD - 1]}"
        else
            echo "$LINE"
        fi
    fi
}

for F in "${FILES[@]}"; do
    if [[ -e $F ]]; then
        if [[ PARSE_SPECIFIC_LINE -gt 0 ]]; then
            parse_line "$(sed -n "${PARSE_SPECIFIC_LINE}{p;q}" "$F")"
        else
            while read -r LINE; do
                parse_line "$LINE"
            done < "$F"
        fi
    else
        echo "File does not exist: $F"
    fi
done

我跑了

bash script.sh -f 2 <(for i in {1..20}; do echo "$RANDOM $RANDOM $RANDOM $RANDOM $RANDOM"; done)

我得到了

1031
1072
4350
12471
31129
32318
...

添加-l 5我得到

11604
于 2013-09-06T18:49:13.723 回答