私のスクリプトでは、間隔を拡張する必要があります。例:
input: 1,5-7
次のようなものを取得するには:
output: 1,5,6,7
ここで他の解決策を見つけましたが、それらにはPythonが含まれており、スクリプトで使用できません。
Bashの範囲拡張を使用できます。たとえば、入力をすでに解析していると仮定すると、一連の連続した操作を実行して、範囲をコンマ区切りの一連に変換できます。例えば:
value1=1
value2='5-7'
value2=${value2/-/..}
value2=`eval echo {$value2}`
echo "input: $value1,${value2// /,}"
evalの危険性に関する通常の警告がすべて当てはまります。この問題は、Perl、Ruby、Python、またはAWKで解決したほうがよいでしょう。できない、またはできない場合は、evalの必要性を回避するために、少なくともtrやsedなどのパイプラインツールを変換に含めることを検討する必要があります。
次のようなものを試してください。
#!/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が述べたように、配列を何度も再作成するよりも、追加する方が望ましい場合があります。
これは複数の範囲でも機能するはずです。
#! /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
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です。
これが私の刺し傷です:
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
基本的にコンマで分割し、各部分を解釈します。次に、最後にコンマを付けて結合します。
#!/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
@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で動作します
他のすべての答えを考慮して、私はこのソリューションを思いつきました。これは、サブシェル(ただし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[@]}