Initial SPLIT-HTTP support

This commit is contained in:
Samuel Huang
2024-08-25 15:12:03 +10:00
parent 651cff5d79
commit ecac780b4f
19 changed files with 336 additions and 30 deletions

3
nginx-proxy.tpl Normal file
View File

@@ -0,0 +1,3 @@
location LOCATION {
proxy_pass http://HOST:PORT;
}

28
run.sh
View File

@@ -10,19 +10,19 @@ XCONF=/tmp/server-xray.json
usage() {
echo "server-xray <server-options>"
echo " --lx <VLESS-XTLS option> [p=443,]d=domain.com,u=id[:level[:email]]"
echo " --lt <VLESS-TLS option> [p=443,]d=domain.com,u=id[:level[:email]]"
echo " --ltw <VLESS-TLS-WS option> [p=443,]d=domain.com,u=id[:level[:email]],w=/wspath"
echo " --lpw <VLESS-PLN-WS option> [p=443,]u=id[:level[:email],]w=/wspath"
echo " --ltg <VLESS-TLS-GRPC option> [p=443,]d=domain.com,u=id[:level[:email]],s=svcname"
echo " --ls <VLESS-TLS option> [p=443,]d=domain.com,u=id[:level[:email]]"
echo " --ms <VMESS-TLS option> [p=443,]d=domain.com,u=id[:level[:email]]"
echo " --ts <TROJAN-TLS option> [p=443,]d=domain.com,u=psw[:level[:email]]"
echo " --lsw <VLESS-TLS-WS option> [p=443,]d=domain.com,u=id[:level[:email]],w=/wspath"
echo " --lsg <VLESS-TLS-GRPC option> [p=443,]d=domain.com,u=id[:level[:email]],s=svcname"
echo " --lss <VLESS-TLS-SPLT option> [p=442,]d=domain.com,u=id[:level[:email]],w=/webpath"
echo " --msw <VMESS-TLS-WS option> [p=443,]d=domain.com,u=id[:level[:email]],w=/wspath"
echo " --tsw <TROJAN-TLS-WS option> [p=443,]d=domain.com,u=psw[:level[:email]],w=/wspath"
echo " --lpw <VLESS-PLN-WS option> [p=443,]u=id[:level[:email]],w=/wspath"
echo " --lpg <VLESS-PLN-GRPC option> [p=443,]u=id[:level[:email]],s=svcname"
echo " --lts <VLESS-TLS-SPLT option> [p=442,]d=domain.com,u=id[:level[:email]],p=/path"
echo " --lps <VLESS-PLN-SPLT option> [p=442,]u=id[:level[:email],]p=/path"
echo " --mt <VMESS-TLS option> [p=443,]d=domain.com,u=id[:level[:email]]"
echo " --mtw <VMESS-TLS-WS option> [p=443,]d=domain.com,u=id[:level[:email]],w=/webpath"
echo " --mpw <VMESS-PLN-WS option> [p=443,]u=id[:level[:email]],w=/webpath"
echo " --tt <TROJAN-TLS option> [p=443,]d=domain.com,u=psw[:level[:email]]"
echo " --ttw <TROJAN-TLS-WS option> [p=443,]d=domain.com,u=psw[:level[:email]],w=/webpath"
echo " --tpw <TROJAN-PLN-WS option> [p=443,]u=psw[:level[:email]],w=/webpath"
echo " --lps <VLESS-PLN-SPLT option> [p=442,]u=id[:level[:email]],w=/webpath"
echo " --mpw <VMESS-PLN-WS option> [p=443,]u=id[:level[:email]],w=/wspath"
echo " --tpw <TROJAN-PLN-WS option> [p=443,]u=psw[:level[:email]],w=/wspath"
echo " --ng-opt <nginx-options> [p=443,]d=domain0.com[,d=domain1.com][...]"
echo " --ng-proxy <nginx-proxy-options> [d=domain0.com,][d=domain1.com][...][h=127.0.0.1,]p=port-backend,l=location,n=ws|grpc|splt"
echo " -u|--user <global-user-options> u=id0[:level[:email]][,u=id1][...]"
@@ -33,7 +33,7 @@ usage() {
echo " -d|--debug [Optional] Start in debug mode with verbose output"
}
TEMP=`getopt -o u:k:r:c:di --long user:,hook:,request-domain:,cert-home:,lx:,lt:,ltw:,lpw:,mt:,mtw:,mpw:,tt:,ttw:,tpw:,ltg:,lpg:,ng-opt:,ng-proxy:,stdin,debug -n "$0" -- $@`
TEMP=`getopt -o u:k:r:c:di --long user:,hook:,request-domain:,cert-home:,lx:,ls:,ms:,ts:,lsw:,lsg:,lss:,msw:,tsw:,lpw:,lpg:,lps:,mpw:,tpw:,ng-opt:,ng-proxy:,stdin,debug -n "$0" -- $@`
if [ $? != 0 ] ; then usage; exit 1 ; fi
eval set -- "$TEMP"
@@ -63,7 +63,7 @@ while true ; do
UOPT+=("$2")
shift 2
;;
--lx|--lt|--ltw|--lpw|--ltg|--lpg|--mt|--mtw|--mpw|--tt|--ttw|--tpw)
--lx|--ls|--ms|--ts|--lsw|--lsg|--lss|--msw|--tsw|--lpw|--lpg|--lps|--mpw|--tpw)
SVC=`echo $1|tr -d '\-\-'`
SVCMD+=("${DIR}server-${SVC}.sh $2")
shift 2

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-ltpg <xconf=xray-config-file>,<port=443>,<user=xxx-xxx[:0[:a@mail.com]]>,<service=svcname>"
echo "Usage: server-lpg <x=xray-config-file>,<p=listen-port>,<u=xxx-xxx[:0[:a@mail.com]]>,<s=svcname>"
}
options=(`echo $1 |tr ',' ' '`)

131
server-lps.sh Executable file
View File

@@ -0,0 +1,131 @@
#!/bin/bash
usage() {
echo "Usage: server-lps <x=xray-config-file>,<p=listen-port>,<u=myid[:0[:a@mail.com]]>,<w=web-path>"
}
options=(`echo $1 |tr ',' ' '`)
for option in "${options[@]}"
do
kv=(`echo $option |tr '=' ' '`)
case "${kv[0]}" in
x|xconf)
xconf="${kv[1]}"
;;
p|port)
port="${kv[1]}"
;;
u|user)
xuser+=("${kv[1]}")
;;
w|wpath)
webpath="${kv[1]}"
;;
f|fallback)
fallback+=("${kv[1]}")
;;
esac
done
if [ -z "${xconf}" ]; then
echo "Error: xconf undefined."
usage
exit 1
fi
if [ -z "${port}" ]; then
port=443
fi
if [ -z "${xuser}" ]; then
echo "Error: user undefined."
usage
exit 1
fi
if [ -z "${webpath}" ]; then
echo "Error: webpath undefined."
usage
exit 1
fi
if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi
XCONF=$xconf
# Remove existing port number if existing.
cat $XCONF |jq --arg port "${port}" 'del( .inbounds[] | select(.port == ($port|tonumber)) )' |sponge $XCONF
cat $XCONF |jq --arg port "${port}" '.inbounds +=[{"port":($port|tonumber), "protocol":"vless", "settings":{"clients":[]}}]' |sponge $XCONF
for xu in "${xuser[@]}"
do
IFS=':'
uopt=(${xu})
uopt=(${uopt[@]})
if [ -z "${uopt[0]}" ]; then
echo "Incorrect user format: ${xu}"
echo "Correct user format: user=<uid>[:level:email]"
echo "Like: user=myid:0:me@g.cn"
echo "Like: user=myid::me@g.cn"
echo "Like: user=myid:0"
echo "Like: user=myid"
exit 1
fi
if [ -z "${uopt[1]}" ]; then
uopt[1]=0
fi
cat $XCONF |jq --arg port "${port}" --arg uid "${uopt[0]}" --arg level "${uopt[1]}" --arg email "${uopt[2]}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.clients ) += [ {"id":$uid, "level":($level|tonumber), "email":$email} ] ' \
|sponge $XCONF
done
cat $XCONF |jq --arg port "${port}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.decryption ) += "none" ' \
|sponge $XCONF
for fb in "${fallback[@]}"
do
IFS=':'
fopt=(${fb})
fopt=(${fopt[@]})
fhost="${fopt[0]}"
fport="${fopt[1]}"
fpath="${fopt[2]}"
if [ -z "${fport}" ]; then
echo "Incorrect fallback format: ${fb}"
echo "Correct fallback: fallback=[host]<:port>[:path]"
echo "Like: fallback=baidu.com:443:/websocket"
echo "Like: fallback=:1443:/websocket"
echo "Like: fallback=:1443"
exit 1
fi
if [ -z "${fhost}" ]; then
if [ -z "${fpath}" ]; then
Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "xver":1}'`
else
Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "path":$fpath, "xver":1}'`
fi
else
if [ -z "${fpath}" ]; then
fdest="${fhost}:${fport}"
Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "xver":1}'`
else
Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "path":$fpath, "xver":1}'`
fi
fi
cat $XCONF |jq --arg port "${port}" --argjson jfallback "$Jfallback" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.fallbacks ) += [ $jfallback ] ' \
|sponge $XCONF
done
cat $XCONF |jq --arg port "${port}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"network":"splithttp", "security":"none" } ' \
|sponge $XCONF
cat $XCONF |jq --arg port "${port}" --arg webpath "${webpath}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"splithttpSettings":{"path":$webpath}} ' \
|sponge $XCONF

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-ltpw <xconf=xray-config-file>,<port=443>,<user=myid[:0[:a@mail.com]]>,<path=websocket-path>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-lpw <x=xray-config-file>,<p=listen-port>,<u=myid[:0[:a@mail.com]]>,<w=websocket-path>"
}
options=(`echo $1 |tr ',' ' '`)

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-ltt <xconf=xray-config-file>,<certhome=cert-home-dir>,<port=443>,<domain=mydomain.com>,<user=xxx-xxx[:0[:a@mail.com]]>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-ls <x=xray-config-file>,<c=cert-home-dir>,<p=listen-port>,<d=mydomain.com>,<u=xxx-xxx[:0[:a@mail.com]]>"
}
options=(`echo $1 |tr ',' ' '`)

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-lttg <xconf=xray-config-file>,<certhome=cert-home-dir>,<port=443>,<domain=mydomain.com>,<user=xxx-xxx[:0[:a@mail.com]]>,<service=svcname>"
echo "Usage: server-lsg <x=xray-config-file>,<c=cert-home-dir>,<p=listen-port>,<d=mydomain.com>,<u=xxx-xxx[:0[:a@mail.com]]>,<s=svcname>"
}
options=(`echo $1 |tr ',' ' '`)

169
server-lss.sh Executable file
View File

@@ -0,0 +1,169 @@
#!/bin/bash
usage() {
echo "Usage: server-lss <x=xray-config-file>,<c=cert-home-dir>,<p=listen-port>,<d=mydomain.com>,<u=xxx-xxx[:0[:a@mail.com]]>,<w=web-path>"
}
options=(`echo $1 |tr ',' ' '`)
for option in "${options[@]}"
do
kv=(`echo $option |tr '=' ' '`)
case "${kv[0]}" in
x|xconf)
xconf="${kv[1]}"
;;
c|certhome)
certhome="${kv[1]}"
;;
p|port)
port="${kv[1]}"
;;
d|domain)
domain="${kv[1]}"
;;
u|user)
xuser+=("${kv[1]}")
;;
w|wpath)
webpath="${kv[1]}"
;;
f|fallback)
fallback+=("${kv[1]}")
;;
esac
done
if [ -z "${certhome}" ]; then
echo "Error: certhome undefined."
usage
exit 1
fi
if [ -z "${xconf}" ]; then
echo "Error: xconf undefined."
usage
exit 1
fi
if [ -z "${port}" ]; then
port=443
fi
if [ -z "${domain}" ]; then
echo "Error: domain undefined."
usage
exit 1
fi
if [ -z "${xuser}" ]; then
echo "Error: user undefined."
usage
exit 1
fi
if [ -z "${webpath}" ]; then
echo "Error: webpath undefined."
usage
exit 1
fi
if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi
XCONF=$xconf
# Remove existing port number if existing.
cat $XCONF |jq --arg port "${port}" 'del( .inbounds[] | select(.port == ($port|tonumber)) )' |sponge $XCONF
cat $XCONF |jq --arg port "${port}" '.inbounds +=[{"port":($port|tonumber), "protocol":"vless", "settings":{"clients":[]}}]' |sponge $XCONF
for xu in "${xuser[@]}"
do
IFS=':'
uopt=(${xu})
uopt=(${uopt[@]})
if [ -z "${uopt[0]}" ]; then
echo "Incorrect user format: ${xu}"
echo "Correct user format: user=<uid>[:level:email]"
echo "Like: user=myid:0:me@g.cn"
echo "Like: user=myid::me@g.cn"
echo "Like: user=myid:0"
echo "Like: user=myid"
exit 1
fi
if [ -z "${uopt[1]}" ]; then
uopt[1]=0
fi
cat $XCONF |jq --arg port "${port}" --arg uid "${uopt[0]}" --arg level "${uopt[1]}" --arg email "${uopt[2]}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.clients ) += [ {"id":$uid, "level":($level|tonumber), "email":$email} ] ' \
|sponge $XCONF
done
cat $XCONF |jq --arg port "${port}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.decryption ) += "none" ' \
|sponge $XCONF
for fb in "${fallback[@]}"
do
IFS=':'
fopt=(${fb})
fopt=(${fopt[@]})
fhost="${fopt[0]}"
fport="${fopt[1]}"
fpath="${fopt[2]}"
if [ -z "${fport}" ]; then
echo "Incorrect fallback format: ${fb}"
echo "Correct fallback: fallback=[host]<:port>[:path]"
echo "Like: fallback=baidu.com:443:/websocket"
echo "Like: fallback=:1443:/websocket"
echo "Like: fallback=:1443"
exit 1
fi
if [ -z "${fhost}" ]; then
if [ -z "${fpath}" ]; then
Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "xver":1}'`
else
Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "path":$fpath, "xver":1}'`
fi
else
if [ -z "${fpath}" ]; then
fdest="${fhost}:${fport}"
Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "xver":1}'`
else
Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "path":$fpath, "xver":1}'`
fi
fi
cat $XCONF |jq --arg port "${port}" --argjson jfallback "$Jfallback" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.fallbacks ) += [ $jfallback ] ' \
|sponge $XCONF
done
cat $XCONF |jq --arg port "${port}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"network":"splithttp", "security":"tls"} ' \
|sponge $XCONF
cat $XCONF |jq --arg port "${port}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"tlsSettings":{"alpn":["http/1.1"]}} ' \
|sponge $XCONF
cat $XCONF |jq --arg port "${port}" --arg webpath "${webpath}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"splithttpSettings":{"path":$webpath}} ' \
|sponge $XCONF
if [ -f "${certhome}/${domain}/fullchain.cer" ] && [ -f "${certhome}/${domain}/${domain}.key" ]; then
fullchain="${certhome}/${domain}/fullchain.cer"
prvkey="${certhome}/${domain}/${domain}.key"
break
fi
if [ ! -f "${fullchain}" ] || [ ! -f "${prvkey}" ]; then
echo "TLS cert missing?"
echo "Abort."
exit 2
fi
cat $XCONF |jq --arg port "${port}" --arg fullchain "${fullchain}" --arg prvkey "${prvkey}" \
'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings.tlsSettings ) += {"certificates":[{"certificateFile":$fullchain, "keyFile":$prvkey}]} ' \
|sponge $XCONF

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-lttw <xconf=xray-config-file>,<certhome=cert-home-dir>,<port=443>,<domain=mydomain.com>,<user=xxx-xxx[:0[:a@mail.com]]>,<path=websocket-path>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-lsw <x=xray-config-file>,<c=cert-home-dir>,<p=listen-port>,<d=mydomain.com>,<u=xxx-xxx[:0[:a@mail.com]]>,<w=websocket-path>"
}
options=(`echo $1 |tr ',' ' '`)

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-ltx <xconf=xray-config-file>,<certhome=cert-home-dir>,<port=443>,<domain=mydomain.com>,<user=xxx-xxx[:0[:a@mail.com]]>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-lx <x=xray-config-file>,<c=cert-home-dir>,<p=listen-port>,<d=mydomain.com>,<u=xxx-xxx[:0[:a@mail.com]]>"
}
options=(`echo $1 |tr ',' ' '`)

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-mtpw <xconf=xray-config-file>,<port=443>,<user=myid[:0[:a@mail.com]]>,<path=websocket-path>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-mpw <x=xray-config-file>,<p=listen-port>,<u=myid[:0[:a@mail.com]]>,<w=websocket-path>"
}
options=(`echo $1 |tr ',' ' '`)

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-mtt <xconf=xray-config-file>,<certhome=cert-home-dir>,<port=443>,<domain=mydomain.com>,<user=xxx-xxx[:0[:a@mail.com]]>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-ms <x=xray-config-file>,<c=cert-home-dir>,<p=listen-port>,<d=mydomain.com>,<u=xxx-xxx[:0[:a@mail.com]]>"
}
options=(`echo $1 |tr ',' ' '`)

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-mttw <xconf=xray-config-file>,<certhome=cert-home-dir>,<port=443>,<domain=mydomain.com>,<user=xxx-xxx[:0[:a@mail.com]]>,<path=websocket-path>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-msw <x=xray-config-file>,<c=cert-home-dir>,<p=listen-port>,<d=mydomain.com>,<u=xxx-xxx[:0[:a@mail.com]]>,<w=websocket-path>"
}
options=(`echo $1 |tr ',' ' '`)

View File

@@ -5,9 +5,9 @@ DIR="$(cd $DIR; pwd)"
TPL="site-ssl.conf.tpl"
usage() {
echo "server-nginx --ng-opt <c=certhome,d=domain>[,p=443] --ng-proxy <p=xport,l=location,n=grpc|ws>[,h=127.0.0.1]"
echo "server-nginx --ng-opt <c=certhome,d=domain>[,p=443] --ng-proxy <p=xport,l=location,n=grpc|ws|splt>[,h=127.0.0.1]"
echo " --ng-opt <c=cert-home-dir,d=host-domain>[,p=443]"
echo " --ng-proxy <p=port-backend,l=location-path,n=grpc|ws>[,h=127.0.0.1][,d=host-domain]"
echo " --ng-proxy <p=port-backend,l=location-path,n=grpc|ws|splt>[,h=127.0.0.1][,d=host-domain]"
}
TEMP=`getopt -o o:x: --long ng-opt:,ng-proxy: -n "$0" -- $@`
@@ -130,10 +130,13 @@ do
# Replace the last(only) single line '}' with specific tpl file, hence insert a new section into the Nginx config file
case "${xnetwork}" in
ws|websocket)
sed -i -e "/^\}$/r ws.tpl" -e "/^\}$/d" ${domain}.conf
sed -i -e "/^\}$/r nginx-ws.tpl" -e "/^\}$/d" ${domain}.conf
;;
grpc)
sed -i -e "/^\}$/r grpc.tpl" -e "/^\}$/d" ${domain}.conf
sed -i -e "/^\}$/r nginx-grpc.tpl" -e "/^\}$/d" ${domain}.conf
;;
splt|proxy)
sed -i -e "/^\}$/r nginx-proxy.tpl" -e "/^\}$/d" ${domain}.conf
;;
esac
# Then add '}' to the end of the Nginx config file

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-ttpw <xconf=xray-config-file>,<port=443>,<user=password[:level[:email]],<path=websocket-path>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-tpw <x=xray-config-file>,<p=listen-port>,<u=password[:level[:email]],<w=websocket-path>"
}
options=(`echo $1 |tr ',' ' '`)

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-ttt <xconf=xray-config-file>,<certhome=cert-home-dir>,<port=443>,<domain=mydomain.com>,<user=password[:level[:email]]>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-ts <x=xray-config-file>,<c=cert-home-dir>,<p=listen-port>,<d=mydomain.com>,<u=password[:level[:email]]>"
}
options=(`echo $1 |tr ',' ' '`)

View File

@@ -1,7 +1,7 @@
#!/bin/bash
usage() {
echo "Usage: server-tttw <xconf=xray-config-file>,<certhome=cert-home-dir>,<port=443>,<domain=mydomain.com>,<user=password[:level[:email]],<path=websocket-path>[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]"
echo "Usage: server-tsw <x=xray-config-file>,<c=cert-home-dir>,<p=listen-port>,<d=mydomain.com>,<u=password[:level[:email]],<w=websocket-path>"
}
options=(`echo $1 |tr ',' ' '`)