2

私のスクリプトでは、間隔を拡張する必要があります。例:

input: 1,5-7

次のようなものを取得するには:

output: 1,5,6,7

ここで他の解決策を見つけましたが、それらにはPythonが含まれており、スクリプトで使用できません。

4

8 に答える 8

2

ジャストバッシュ4ビルトインによるソリューション

Bashの範囲拡張を使用できます。たとえば、入力をすでに解析していると仮定すると、一連の連続した操作を実行して、範囲をコンマ区切りの一連に変換できます。例えば:

value1=1
value2='5-7'
value2=${value2/-/..}
value2=`eval echo {$value2}`
echo "input: $value1,${value2// /,}"

evalの危険性に関する通常の警告がすべて当てはまります。この問題は、Perl、Ruby、Python、またはAWKで解決したほうがよいでしょう。できない、またはできない場合は、evalの必要性を回避するために、少なくともtrsedなどのパイプラインツールを変換に含めることを検討する必要があります。

于 2013-03-09T18:08:14.243 に答える
2

次のようなものを試してください。

#!/bin/bash

for f in ${1//,/ }; do
  if [[ $f =~ - ]]; then
    a+=( $(seq ${f%-*} 1 ${f#*-}) )
  else
    a+=( $f )
  fi  
done

a=${a[*]}
a=${a// /,}

echo $a

編集:コメントで@Maxim_unitedが述べたように、配列を何度も再作成するよりも、追加する方が望ましい場合があります。

于 2013-03-09T18:12:57.077 に答える
1

これは複数の範囲でも機能するはずです。

#! /bin/bash
input="1,5-7,13-18,22"
result_str=""
for num in $(tr ',' ' ' <<< "$input"); do
    if [[ "$num" == *-* ]]; then
        res=$(seq -s ',' $(sed -n 's#\([0-9]\+\)-\([0-9]\+\).*#\1 \2#p' <<< "$num"))
    else
        res="$num"
    fi
    result_str="$result_str,$res"
done
echo ${result_str:1}

次の出力が生成されます。

1,5,6,7,13,14,15,16,17,18,22
于 2013-03-09T18:24:45.970 に答える
0
expand_commas()
{
    local arg
    local st en i

    set -- ${1//,/ }
    for arg
    do
        case $arg in
        [0-9]*-[0-9]*)
            st=${arg%-*}
            en=${arg#*-}
            for ((i = st; i <= en; i++))
            do
                echo $i
            done
        ;;
        *)
            echo $arg
        ;;
        esac
    done
}

使用法:

result=$(expand_commas arg)

例えば:

result=$(expand_commas 1,5-7,9-12,3)
echo $result

もちろん、区切り単語をコンマに戻す必要があります。

入力が悪いと少し壊れやすいですが、完全にbashです。

于 2013-03-09T18:02:48.777 に答える
0

これが私の刺し傷です:

input=1,5-7,10,17-20
IFS=, read -a chunks <<< "$input"

output=()
for chunk in "${chunks[@]}"
do
    IFS=- read -a args <<< "$chunk"
    if (( ${#args[@]} == 1 )) # single number                                   
    then
        output+=(${args[*]})
    else # range                                                                
        output+=($(seq "${args[@]}"))
    fi
done
joined=$(sed -e 's/ /,/g' <<< "${output[*]}")
echo $joined

基本的にコンマで分割し、各部分を解釈します。次に、最後にコンマを付けて結合します。

于 2013-03-09T18:09:58.937 に答える
0

シーケンス式`{x..y}'を使用した一般的なbashソリューション

#!/bin/bash
function doIt() {
  local inp="${@/,/ }"
  declare -a args=( $(echo ${inp/-/..}) )
  local item
  local sep
  for item in "${args[@]}"
  do
    case ${item} in
        *..*)  eval "for i in {${item}} ; do echo -n \${sep}\${i}; sep=, ; done";;
        *) echo -n ${sep}${item};;
    esac
    sep=,
  done
}
doIt "1,5-7"
  • 質問のサンプルに続く任意の入力で機能する必要があります。また、複数回発生しますx-y
  • bashビルトインのみを使用してください
于 2013-03-09T18:21:05.000 に答える
0

@Ansgar Wiechersと@CodeGnomeの両方のアイデアを使用する:

input="1,5-7,13-18,22"
for s in ${input//,/ }
do
    if [[ $f =~ - ]]
    then
        a+=( $(eval echo {${s//-/..}}) )
    else
        a+=( $s )
    fi  
done
oldIFS=$IFS; IFS=$','; echo "${a[*]}"; IFS=$oldIFS

Bash3で動作します

于 2015-04-30T15:27:09.480 に答える
0

他のすべての答えを考慮して、私はこのソリューションを思いつきました。これは、サブシェル(ただしeval、ブレース拡張の1つの呼び出し)または個別のプロセスを使用しません。

# range list is assumed to be in $1 (e.g. 1-3,5,9-13)

# convert $1 to an array of ranges ("1-3" "5" "9-13")
IFS=,
local range=($1)
unset IFS

list=() # initialize result list
local r
for r in "${range[@]}"; do
    if [[ $r == *-* ]]; then
        # if the range is of the form "x-y",
        # * convert to a brace expression "{x..y}",
        # * using eval, this gets expanded to "x" "x+1" … "y" and
        # * append this to the list array
        eval list+=( {${r/-/..}} )
    else
        # otherwise, it is a simple number and can be appended to the array
        list+=($r)
    fi
done

# test output
echo ${list[@]}
于 2016-08-23T12:29:19.453 に答える