# Bash command completion for /bin/ip utility from iproute2-ss041019 # # Version 0.1: Ugly but somewhat functional # # All options except that ones for xfrm state/policy are supported. # # BUGS: # It often suggests too many context. # Does not take into account current cursor position on a command line (always # completes the last word). # # TODO: # Completion for xfrm state/policy options. # Completion for non-keywords: currently has devices completion (everywhere) # defined addresses completion in "ip addr del" # and filename completion in "ip monitor file". # More efficient and nice code. # # -- Alexej Sveshnikov Wed, 7 Dec 2005 have ip && { # Usage: ip [ OPTIONS ] OBJECT { COMMAND | help } # where OBJECT := { link | addr | route | rule | neigh | tunnel | # maddr | mroute | monitor | xfrm } # OPTIONS := { -V[ersion] | -s[tatistics] | -r[esolve] | # -f[amily] { inet | inet6 | ipx | dnet | link } | -o[neline] } _iproute() { local where i cur OPTIONS OBJECT COMPREPLY=() where=OPTIONS for (( i=1 ; i<=COMP_CWORD ; i++ )) ; do cur="${COMP_WORDS[i]}" case "$cur" in -f|-family) where=FAMILY_OPT ;; -*) where=OPTIONS ;; *) if [ $where == FAMILY_OPT ] ; then where=FAMILY else where=OBJECT break fi ;; esac done if [ $where == OBJECT -a "${COMP_WORDS[i]}" == "" ] ; then where=OPTIONS fi OPTIONS="-Version -statistics -resolve -family -oneline" OBJECT="link addr route rule neigh tunnel maddr mroute monitor xfrm" case $where in OPTIONS|FAMILY_OPT) COMPREPLY=( $(compgen -W "$OPTIONS $OBJECT" -- $cur) ) ;; FAMILY) COMPREPLY=( $(compgen -W "inet inet6 ipx dnet link" -- $cur) ) ;; OBJECT) if [[ $i -ge $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "$OBJECT" -- $cur) ) else i=$((i+1)) case "$cur" in link) _ip_obj_link $i ;; addr) _ip_obj_addr $i ;; route) _ip_obj_route $i ;; rule) _ip_obj_rule $i ;; neigh) _ip_obj_neigh $i ;; tunnel) _ip_obj_tunnel $i ;; maddr) _ip_obj_maddr $i ;; mroute) _ip_obj_mroute $i ;; monitor)_ip_obj_monitor $i ;; xfrm) _ip_obj_xfrm $i ;; esac fi ;; esac return 0 } # The same function as _available_interfaces() from the standart bash_completion package # but uses /bin/ip instead of /sbin/ifconfig _ip_available_interfaces() { COMPREPLY=( $( ip link show | \ sed -ne 's|^[[:digit:]]\{1,\}:[[:space:]]*\('"$1"'[^:]*\):.*$|\1|p') ) return 0 } # Checks the COMP_LINE for 'dev DEVICE' part. # If no device is specified on the command line then just silently exits. # Otherwise extracts the information about assigned DEVICE's addresses. # This is done by parsing the "/bin/ip addr show" output. # The typical line with address looks like this: # inet 123.231.132.213/32 scope global eth0 _ip_available_addresses() { local dev dev=$( echo $COMP_LINE | sed -ne 's|^.*[[:space:]]dev[[:space:]]\{1,\}\([^[:space:]]*\).*$|\1|p') if [ -n "$dev" ] ; then ip addr show | \ sed -ne 's|^ \{1,\}[^ ]* \{1,\}\([^ ]*\).* '"$dev"':\?[[:digit:]]*$|\1|p' fi return 0 } # Usage: ip link set DEVICE { up | down | # arp { on | off } | # dynamic { on | off } | # multicast { on | off } | # allmulticast { on | off } | # promisc { on | off } | # trailers { on | off } | # txqueuelen PACKETS | # name NEWNAME | # address LLADDR | broadcast LLADDR | # mtu MTU } # ip link show [ DEVICE ] _ip_obj_link() { local i cur last i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help set show" -- $cur) ) return 0 fi i=$((i+1)) case "$cur" in show) if [[ $i == $COMP_CWORD ]] ; then _ip_available_interfaces "${COMP_WORDS[i]}" fi ;; set) if [[ $i == $COMP_CWORD ]] ; then _ip_available_interfaces "${COMP_WORDS[i]}" return 0 fi last="${COMP_WORDS[COMP_CWORD]}" case "${COMP_WORDS[COMP_CWORD-1]}" in arp|dynamic|multicast|allmulticast|promisc|trailers) COMPREPLY=( $(compgen -W "on off" -- $last) ) ;; txqueuelen|name|address|broadcast|mtu) ;; *) COMPREPLY=( $(compgen -W "up down arp dynamic multicast allmulticast\ promisc trailers txqueuelen name address broadcast mtu" -- $last) ) ;; esac esac return 0 } # Usage: ip addr {add|del} IFADDR dev STRING # ip addr {show|flush} [ dev STRING ] [ scope SCOPE-ID ] # [ to PREFIX ] [ FLAG-LIST ] [ label PATTERN ] # IFADDR := PREFIX | ADDR peer PREFIX # [ broadcast ADDR ] [ anycast ADDR ] # [ label STRING ] [ scope SCOPE-ID ] # SCOPE-ID := [ host | link | global | NUMBER ] # FLAG-LIST := [ FLAG-LIST ] FLAG # FLAG := [ permanent | dynamic | secondary | primary | # tentative | deprecated ] _ip_obj_addr() { local i cur last addr SCOPE FLAGS i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help add del show flush" -- $cur) ) return 0 fi last="${COMP_WORDS[COMP_CWORD]}" SCOPE="host link global" FLAGS="permanent dynamic secondary primary tentative deprecated" case "$cur" in add|del) case "${COMP_WORDS[COMP_CWORD-1]}" in dev) _ip_available_interfaces "$last" ;; scope) COMPREPLY=( $(compgen -W "$SCOPE" -- $last) ) ;; peer|broadcast|anycast|label) ;; *) if [ "$cur" == "del" ] ; then addr=$(_ip_available_addresses) fi COMPREPLY=( $(compgen -W "dev peer broadcast anycast label scope $addr" -- $last) ) ;; esac ;; show|flush) case "${COMP_WORDS[COMP_CWORD-1]}" in dev) _ip_available_interfaces "$last" ;; scope) COMPREPLY=( $(compgen -W "$SCOPE" -- $last) ) ;; to|label) ;; *) COMPREPLY=( $(compgen -W "dev scope to label $FLAGS" -- $last) ) ;; esac ;; esac return 0 } # Usage: ip route { list | flush } SELECTOR # ip route get ADDRESS [ from ADDRESS iif STRING ] # [ oif STRING ] [ tos TOS ] # ip route { add | del | change | append | replace | monitor } ROUTE # SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ] # [ table TABLE_ID ] [ proto RTPROTO ] # [ type TYPE ] [ scope SCOPE ] # ROUTE := NODE_SPEC [ INFO_SPEC ] # NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ] # [ table TABLE_ID ] [ proto RTPROTO ] # [ scope SCOPE ] [ metric METRIC ] # INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]... # NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS # OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] # [ rtt NUMBER ] [ rttvar NUMBER ] # [ window NUMBER] [ cwnd NUMBER ] [ ssthresh REALM ] # [ realms REALM ] [ hoplimit NUMBER ] [ initcwnd NUMBER ] # TYPE := [ unicast | local | broadcast | multicast | throw | # unreachable | prohibit | blackhole | nat ] # TABLE_ID := [ local | main | default | all | NUMBER ] # SCOPE := [ host | link | global | NUMBER ] # FLAGS := [ equalize ] # NHFLAGS := [ onlink | pervasive ] # RTPROTO := [ kernel | boot | static | NUMBER ] _ip_obj_route() { local i cur last SELECTOR NH OPTIONS TYPE TABLE SCOPE FLAGS NHFLAGS RTPROTO i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help list flush get add del change append replace monitor" -- $cur) ) return 0 fi last="${COMP_WORDS[COMP_CWORD]}" SELECTOR="root match exact table proto type scope" NH="via dev weight" OPTIONS="mtu advmss rtt rttvar window cwnd ssthresh realms hoplimit initcwnd" TYPE="unicast local broadcast multicast throw unreachable prohibit blackhole nat" TABLE="local main default all" SCOPE="host link global" FLAGS="equalize" NHFLAGS="onlink pervasive" RTPROTO="kernel boot static" case "$cur" in list|flush) case "${COMP_WORDS[COMP_CWORD-1]}" in table) COMPREPLY=( $(compgen -W "$TABLE" -- $last) ) ;; proto) COMPREPLY=( $(compgen -W "$RTPROTO" -- $last) ) ;; type) COMPREPLY=( $(compgen -W "$TYPE" -- $last) ) ;; scope) COMPREPLY=( $(compgen -W "$SCOPE" -- $last) ) ;; root|match|exact) ;; *) COMPREPLY=( $(compgen -W "$SELECTOR" -- $last) ) ;; esac ;; get) if [ "${COMP_WORDS[COMP_CWORD-2]}" == "from" ] ; then COMPREPLY=( $(compgen -W "iif" -- $last) ) else case "${COMP_WORDS[COMP_CWORD-1]}" in get|from|iif|oif|tos) ;; *) COMPREPLY=( $(compgen -W "get from oif tos" -- $last) ) ;; esac fi ;; add|del|change|append|replace|monitor) i=$((i+1)) if [ $i == $COMP_CWORD ] ; then COMPREPLY=( $(compgen -W "$TYPE" -- $last) ) return 0 fi case "${COMP_WORDS[COMP_CWORD-1]}" in proto) COMPREPLY=( $(compgen -W "$RTPROTO" -- $last) ) ;; scope) COMPREPLY=( $(compgen -W "$SCOPE" -- $last) ) ;; dev) _ip_available_interfaces "$last" ;; tos|table|metric|via|weight|mtu|advmss|rtt|rttvar) ;; window|cwnd|ssthresh|realms|hoplimit|initcwnd) ;; nexthop) COMPREPLY=( $(compgen -W "$NH $NHFLAGS" -- $last) ) ;; add|del|change|append|replace|monitor) COMPREPLY=( $(compgen -W "$TYPE" -- $last) ) ;; *) COMPREPLY=( $(compgen -W "tos table proto scope metric $NH nexthop \ $OPTIONS $FLAGS" -- $last) ) ;; esac ;; esac return 0 } # Usage: ip rule [ list | add | del ] SELECTOR ACTION # SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK ] # [ dev STRING ] [ pref NUMBER ] # ACTION := [ table TABLE_ID ] [ nat ADDRESS ] # [ prohibit | reject | unreachable ] # [ realms [SRCREALM/]DSTREALM ] # TABLE_ID := [ local | main | default | NUMBER ] _ip_obj_rule() { local i cur last i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help list add del" -- $cur) ) return 0 fi last="${COMP_WORDS[COMP_CWORD]}" case "${COMP_WORDS[COMP_CWORD-1]}" in add|del) COMPREPLY=( $(compgen -W "from to tos fwmark dev pref" -- $last) ) ;; dev) _ip_available_interfaces "$last" ;; table) COMPREPLY=( $(compgen -W "local main default" -- $last) ) ;; help|list|from|to|tos|fwmark|pref|nat|realms) ;; *) COMPREPLY=( $(compgen -W "from to tos fwmark dev pref table nat \ prohibit reject unreachable realms" -- $last) ) ;; esac return 0 } # Usage: ip neigh { add | del | change | replace } { ADDR [ lladdr LLADDR ] # [ nud { permanent | noarp | stale | reachable } ] # | proxy ADDR } [ dev DEV ] # ip neigh {show|flush} [ to PREFIX ] [ dev DEV ] [ nud STATE ] _ip_obj_neigh() { local i cur last i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help add del change replace show flush" -- $cur) ) return 0 fi last="${COMP_WORDS[COMP_CWORD]}" case "${COMP_WORDS[COMP_CWORD-1]}" in help|lladdr|proxy|to) ;; add|del|change|replace) COMPREPLY=( $(compgen -W "proxy" -- $last) ) ;; nud) COMPREPLY=( $(compgen -W "permanent noarp stale reachable" -- $last) ) ;; dev) _ip_available_interfaces "$last" ;; show|flush) COMPREPLY=( $(compgen -W "to dev nud" -- $last) ) ;; *) if [ "$cur" == "show" -o "$cur" == "flush" ] ; then COMPREPLY=( $(compgen -W "to dev nud" -- $last) ) else COMPREPLY=( $(compgen -W "lladdr nud dev" -- $last) ) fi ;; esac return 0 } # Usage: ip tunnel { add | change | del | show } [ NAME ] # [ mode { ipip | gre | sit } ] [ remote ADDR ] [ local ADDR ] # [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ] # [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ] # # Where: NAME := STRING # ADDR := { IP_ADDRESS | any } # TOS := { NUMBER | inherit } # TTL := { 1..255 | inherit } # KEY := { DOTTED_QUAD | NUMBER } _ip_obj_tunnel() { local i cur last i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help add change del show" -- $cur) ) return 0 fi last="${COMP_WORDS[COMP_CWORD]}" case "${COMP_WORDS[COMP_CWORD-1]}" in help|remote|local|[io]key|[io]csum|ttl|tos) ;; mode) COMPREPLY=( $(compgen -W "ipip gre sit" -- $last) ) ;; dev) _ip_available_interfaces "$last" ;; *) COMPREPLY=( $(compgen -W "mode remote local iseq oseq ikey okey \ icsum ocsum ttl tos pmtudisc nopmtudisc dev" -- $last) ) ;; esac return 0 } # Usage: ip maddr [ add | del ] MULTIADDR dev STRING # ip maddr show [ dev STRING ] _ip_obj_maddr() { local i cur last i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help add del show" -- $cur) ) return 0 fi last="${COMP_WORDS[COMP_CWORD]}" case "${COMP_WORDS[COMP_CWORD-1]}" in show) COMPREPLY=( $(compgen -W "dev" -- $last) ) ;; dev) _ip_available_interfaces "$last" ;; esac return 0 } # Usage: ip mroute show [ PREFIX ] [ from PREFIX ] [ iif DEVICE ] _ip_obj_mroute() { local i cur last i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help show" -- $cur) ) return 0 fi last="${COMP_WORDS[COMP_CWORD]}" case "${COMP_WORDS[COMP_CWORD-1]}" in from) ;; iif) _ip_available_interfaces "$last" ;; *) COMPREPLY=( $(compgen -W "from iif" -- $last) ) ;; esac return 0 } # Usage: ip monitor [ all | LISTofOBJECTS ] # From the ip(8) man page: # OBJECT-LIST is the list of object types that we want to monitor. # It may contain 'link', 'address' and 'route'. If no 'file' argument is given, # ip opens RTNETLINK, listens on it and dumps state changes in the format # described in previous sections. _ip_obj_monitor() { local i cur i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help all link address route file" -- $cur) ) fi if [ "${COMP_WORDS[COMP_CWORD-1]}" == "file" ] ; then cur="${COMP_WORDS[COMP_CWORD]}" _filedir fi return 0 } # Usage: ip xfrm XFRM_OBJECT { COMMAND | help } # where XFRM_OBJECT := { state | policy } # # TODO: ip xfrm state help ; ip xfrm policy help _ip_obj_xfrm() { local i cur last i=$1 cur="${COMP_WORDS[i]}" if [[ $i == $COMP_CWORD ]] ; then COMPREPLY=( $(compgen -W "help state policy" -- $cur) ) fi return 0 } complete -F _iproute ip }