@@ -673,6 +673,46 @@ _comp_compgen_set()
673673 eval -- " $_var ${_append: ++} =(\"\$ @\" )"
674674}
675675
676+ # Simply split the text and generate completions. This function should be used
677+ # instead of `_comp_compgen -- -W "$(command)"`, which is vulnerable because
678+ # option -W evaluates the shell expansions included in the option argument.
679+ # Options:
680+ # -F sep Specify the separators. The default is $' \t\n'
681+ # -l The same as -F $'\n'
682+ # -X arg The same as the compgen option -X.
683+ # -S arg The same as the compgen option -S.
684+ # -P arg The same as the compgen option -P.
685+ # -o arg The same as the compgen option -o.
686+ # @param $1 String to split
687+ # @since 2.12
688+ _comp_compgen_split ()
689+ {
690+ local _ifs=$' \t\n '
691+ local -a _compgen_options=()
692+
693+ local OPTIND=1 OPTARG=" " OPTERR=0 _opt
694+ while getopts ' :lF:X:S:P:o:' _opt " $@ " ; do
695+ case $_opt in
696+ l) _ifs=$' \n ' ;;
697+ F) _ifs=$OPTARG ;;
698+ [XSPo]) _compgen_options+=(" -$_opt " " $OPTARG " ) ;;
699+ * )
700+ printf ' bash_completion: usage: %s [-l|-F sep] [--] str\n' " $FUNCNAME " >&2
701+ return 2
702+ ;;
703+ esac
704+ done
705+ shift " $(( OPTIND - 1 )) "
706+ if (( $# != 1 )) ; then
707+ printf ' bash_completion: %s: unexpected number of arguments.\n' " $FUNCNAME " >&2
708+ printf ' usage: %s [-l|-F sep] [--] str' " $FUNCNAME " >&2
709+ return 2
710+ fi
711+
712+ local _split_input=$1 IFS=$' \t\n '
713+ _comp_compgen -F " $_ifs " -- ${_compgen_options[@]+" ${_compgen_options[@]} " } -W ' $_split_input'
714+ }
715+
676716# Check if the argument looks like a path.
677717# @param $1 thing to check
678718# @return True (0) if it does, False (> 0) otherwise
@@ -1183,7 +1223,7 @@ _comp_variable_assignments()
11831223 _terms
11841224 ;;
11851225 LANG | LC_* )
1186- _comp_compgen -- -W ' $(locale -a 2>/dev/null)'
1226+ _comp_compgen_split -- " $( locale -a 2> /dev/null) "
11871227 ;;
11881228 LANGUAGE)
11891229 _comp_delimited : -W ' $(locale -a 2>/dev/null)'
@@ -1524,23 +1564,23 @@ _configured_interfaces()
15241564 # Debian system
15251565 _comp_expand_glob files ' /etc/network/interfaces /etc/network/interfaces.d/*'
15261566 (( ${# files[@]} )) || return 0
1527- _comp_compgen -- -W " $( command sed -ne ' s|^iface \([^ ]\{1,\}\).*$|\1|p ' \
1528- " ${files[@]} " 2> /dev/null) "
1567+ _comp_compgen_split -- " $( command sed -ne \
1568+ ' s|^iface \([^ ]\{1,\}\).*$|\1|p ' " ${files[@]} " 2> /dev/null) "
15291569 elif [[ -f /etc/SuSE-release ]]; then
15301570 # SuSE system
15311571 _comp_expand_glob files ' /etc/sysconfig/network/ifcfg-*'
15321572 (( ${# files[@]} )) || return 0
1533- _comp_compgen -- -W " $( printf ' %s\n' " ${files[@]} " |
1573+ _comp_compgen_split -- " $( printf ' %s\n' " ${files[@]} " |
15341574 command sed -ne ' s|.*ifcfg-\([^*].*\)$|\1|p' ) "
15351575 elif [[ -f /etc/pld-release ]]; then
15361576 # PLD Linux
1537- _comp_compgen -- -W " $( command ls -B /etc/sysconfig/interfaces |
1577+ _comp_compgen_split -- " $( command ls -B /etc/sysconfig/interfaces |
15381578 command sed -ne ' s|.*ifcfg-\([^*].*\)$|\1|p' ) "
15391579 else
15401580 # Assume Red Hat
15411581 _comp_expand_glob files ' /etc/sysconfig/network-scripts/ifcfg-*'
15421582 (( ${# files[@]} )) || return 0
1543- _comp_compgen -- -W " $( printf ' %s\n' " ${files[@]} " |
1583+ _comp_compgen_split -- " $( printf ' %s\n' " ${files[@]} " |
15441584 command sed -ne ' s|.*ifcfg-\([^*].*\)$|\1|p' ) "
15451585 fi
15461586}
@@ -1576,7 +1616,7 @@ _ip_addresses()
15761616# TODO:API: rename per conventions
15771617_kernel_versions ()
15781618{
1579- _comp_compgen -- -W ' $(command ls /lib/modules)'
1619+ _comp_compgen_split -- " $( command ls /lib/modules) "
15801620}
15811621
15821622# This function completes on all available network interfaces
@@ -1694,26 +1734,26 @@ if [[ $OSTYPE == *@(solaris|aix)* ]]; then
16941734 # This function completes on process IDs.
16951735 _pids ()
16961736 {
1697- _comp_compgen -- -W ' $(command ps -efo pid | command sed 1d)'
1737+ _comp_compgen_split -- " $( command ps -efo pid | command sed 1d) "
16981738 }
16991739
17001740 _pgids ()
17011741 {
1702- _comp_compgen -- -W ' $(command ps -efo pgid | command sed 1d)'
1742+ _comp_compgen_split -- " $( command ps -efo pgid | command sed 1d) "
17031743 }
17041744 _pnames ()
17051745 {
1706- _comp_compgen -- - X ' <defunct>' -W ' $(command ps -efo comm | \
1707- command sed -e 1d -e " s:.*/::" -e " s/^-//" | sort -u)'
1746+ _comp_compgen_split - X ' <defunct>' -- " $( command ps -efo comm |
1747+ command sed -e 1d -e ' s:.*/::' -e ' s/^-//' | sort -u) "
17081748 }
17091749else
17101750 _pids ()
17111751 {
1712- _comp_compgen -- -W ' $(command ps ax -o pid=)'
1752+ _comp_compgen_split -- " $( command ps ax -o pid=) "
17131753 }
17141754 _pgids ()
17151755 {
1716- _comp_compgen -- -W ' $(command ps ax -o pgid=)'
1756+ _comp_compgen_split -- " $( command ps ax -o pgid=) "
17171757 }
17181758 # @param $1 if -s, don't try to avoid truncated command names
17191759 _pnames ()
@@ -1772,12 +1812,12 @@ fi
17721812_uids ()
17731813{
17741814 if type getent & > /dev/null; then
1775- _comp_compgen -- -W ' $(getent passwd | cut -d: -f3)'
1815+ _comp_compgen_split -- " $( getent passwd | cut -d: -f3) "
17761816 elif type perl & > /dev/null; then
1777- _comp_compgen -- -W ' $(perl -e ' " ' " ' while (($uid) = (getpwent)[2]) { print $uid . "\n" }' " ' " ' ) '
1817+ _comp_compgen_split -- " $( perl -e ' while (($uid) = (getpwent)[2]) { print $uid . "\n" }' ) "
17781818 else
17791819 # make do with /etc/passwd
1780- _comp_compgen -- -W ' $(cut -d: -f3 /etc/passwd)'
1820+ _comp_compgen_split -- " $( cut -d: -f3 /etc/passwd) "
17811821 fi
17821822}
17831823
@@ -1787,12 +1827,12 @@ _uids()
17871827_gids ()
17881828{
17891829 if type getent & > /dev/null; then
1790- _comp_compgen -- -W ' $(getent group | cut -d: -f3)'
1830+ _comp_compgen_split -- " $( getent group | cut -d: -f3) "
17911831 elif type perl & > /dev/null; then
1792- _comp_compgen -- -W ' $(perl -e ' " ' " ' while (($gid) = (getgrent)[2]) { print $gid . "\n" }' " ' " ' ) '
1832+ _comp_compgen_split -- " $( perl -e ' while (($gid) = (getgrent)[2]) { print $gid . "\n" }' ) "
17931833 else
17941834 # make do with /etc/group
1795- _comp_compgen -- -W ' $(cut -d: -f3 /etc/group)'
1835+ _comp_compgen_split -- " $( cut -d: -f3 /etc/group) "
17961836 fi
17971837}
17981838
@@ -1862,9 +1902,9 @@ _service()
18621902 else
18631903 local sysvdirs
18641904 _comp_sysvdirs
1865- _comp_compgen -l -- -W ' $(command sed -e " y/|/ /" \
1866- -ne " s/^.*\(U\|msg_u\)sage.*{\(.*\)}.*$/\2/p" \
1867- ${sysvdirs[0]}/${prev##*/} 2>/dev/null) start stop'
1905+ _comp_compgen_split -l -- " $( command sed -e ' y/|/ /' \
1906+ -ne ' s/^.*\(U\|msg_u\)sage.*{\(.*\)}.*$/\2/p' \
1907+ " ${sysvdirs[0]} /${prev##*/ } " 2> /dev/null) start stop"
18681908 fi
18691909} &&
18701910 complete -F _service service
@@ -1889,7 +1929,7 @@ _modules()
18891929{
18901930 local modpath
18911931 modpath=/lib/modules/$1
1892- _comp_compgen -- -W " $( command ls -RL " $modpath " 2> /dev/null |
1932+ _comp_compgen_split -- " $( command ls -RL " $modpath " 2> /dev/null |
18931933 command sed -ne ' s/^\(.*\)\.k\{0,1\}o\(\.[gx]z\)\{0,1\}$/\1/p' \
18941934 -e ' s/^\(.*\)\.ko\.zst$/\1/p' ) "
18951935}
@@ -1899,7 +1939,7 @@ _modules()
18991939# TODO:API: rename per conventions (+ include "kernel" in the name)
19001940_installed_modules ()
19011941{
1902- _comp_compgen -c " $1 " -- -W " $( PATH=" $PATH :/sbin" lsmod |
1942+ _comp_compgen -c " $1 " split -- " $( PATH=" $PATH :/sbin" lsmod |
19031943 awk ' {if (NR != 1) print $1}' ) "
19041944}
19051945
@@ -1961,8 +2001,8 @@ _allowed_users()
19612001 if _complete_as_root; then
19622002 _comp_compgen -c " ${1:- $cur } " -- -u
19632003 else
1964- _comp_compgen -c " ${1:- $cur } " -- -W \
1965- " $( id -un 2> /dev/null || whoami 2> /dev/null) "
2004+ _comp_compgen -c " ${1:- $cur } " split -- " $( id -un 2> /dev/null ||
2005+ whoami 2> /dev/null) "
19662006 fi
19672007}
19682008
@@ -1972,17 +2012,16 @@ _allowed_groups()
19722012 if _complete_as_root; then
19732013 _comp_compgen -c " $1 " -- -g
19742014 else
1975- _comp_compgen -c " $1 " -- -W \
1976- " $( id -Gn 2> /dev/null || groups 2> /dev/null) "
2015+ _comp_compgen -c " $1 " split -- " $( id -Gn 2> /dev/null ||
2016+ groups 2> /dev/null) "
19772017 fi
19782018}
19792019
19802020# @since 2.12
19812021_comp_selinux_users ()
19822022{
1983- _comp_compgen -a -- -W ' $(
1984- semanage user -nl 2>/dev/null | awk "{ print \$1 }"
1985- )'
2023+ _comp_compgen -a split -- " $( semanage user -nl 2> /dev/null |
2024+ awk ' { print $1 }' ) "
19862025}
19872026
19882027# This function completes on valid shells
@@ -2107,15 +2146,16 @@ _count_args()
21072146# TODO:API: rename per conventions
21082147_pci_ids ()
21092148{
2110- _comp_compgen -a -- -W " $( PATH=" $PATH :/sbin" lspci -n | awk ' {print $3}' ) "
2149+ _comp_compgen -a split -- " $( PATH=" $PATH :/sbin" lspci -n |
2150+ awk ' {print $3}' ) "
21112151}
21122152
21132153# This function completes on USB IDs
21142154#
21152155# TODO:API: rename per conventions
21162156_usb_ids ()
21172157{
2118- _comp_compgen -a -- -W " $( PATH=" $PATH :/sbin" lsusb | awk ' {print $6}' ) "
2158+ _comp_compgen -a split -- " $( PATH=" $PATH :/sbin" lsusb | awk ' {print $6}' ) "
21192159}
21202160
21212161# CD device names
@@ -2136,7 +2176,7 @@ _dvd_devices()
21362176# TODO:API: rename per conventions
21372177_terms ()
21382178{
2139- _comp_compgen -a -- -W " $( {
2179+ _comp_compgen -a split -- " $( {
21402180 command sed -ne ' s/^\([^[:space:]#|]\{2,\}\)|.*/\1/p' /etc/termcap
21412181 {
21422182 toe -a || toe
@@ -2694,7 +2734,7 @@ _comp_longopt()
26942734 [[ $was_split ]] && return
26952735
26962736 if [[ $cur == -* ]]; then
2697- _comp_compgen -- -W " $( LC_ALL=C $1 --help 2>&1 |
2737+ _comp_compgen_split -- " $( LC_ALL=C $1 --help 2>&1 |
26982738 while read -r line; do
26992739 [[ $line =~ --[A-Za-z0-9]+ ([-_][A-Za-z0-9]+)* = ? ]] &&
27002740 printf ' %s\n' " ${BASH_REMATCH[0]} "
0 commit comments