diff --git a/docs/ChangeLog.md b/docs/ChangeLog.md index 4c84576d..8bec2af2 100644 --- a/docs/ChangeLog.md +++ b/docs/ChangeLog.md @@ -156,6 +156,7 @@ - edit: fix fd broken by ble-attach of new session in user space (reported by JohEngstrom) `#D2271` 49f97618 670c7ea0 - util (`ble-import`): do not specify arguments to `-C callback` `#D2277` 4f0e94a2 - main: fix issues with `ble/bin/awk` (reported by devidw) `#D2292` b0a7adcb +- util (`ble/path#remove-glob`): fix a bug that `*` matches and removes multiple paths `#D2310` xxxxxxxx ## Compatibility diff --git a/lib/test-util.sh b/lib/test-util.sh index 2246dc5d..903225cc 100644 --- a/lib/test-util.sh +++ b/lib/test-util.sh @@ -2,7 +2,7 @@ ble-import lib/core-test -ble/test/start-section 'ble/util' 1243 +ble/test/start-section 'ble/util' 1244 # bleopt @@ -931,6 +931,8 @@ function is-global { (builtin readonly "$1"; ! local "$1" 2>/dev/null); } ble/test code:'ret=stdX:stdY:usrZ; ble/path#remove-glob ret "std[a-zX-Z]"' ret=usrZ ble/test code:'ret=stdX:usrZ:stdY; ble/path#remove-glob ret "std[a-zX-Z]"' ret=usrZ ble/test code:'ret=usrZ:stdX:stdY; ble/path#remove-glob ret "std[a-zX-Z]"' ret=usrZ + + ble/test code:'ret=/usr/bin:/usr/local/bin:/usr/sbin:/usr/local/sbin; ble/path#remove-glob ret "/usr/local/*"' ret=/usr/bin:/usr/sbin ) # ble/path#{append,prepend,contains} diff --git a/note.txt b/note.txt index 941930be..d1e2a5b6 100644 --- a/note.txt +++ b/note.txt @@ -7730,6 +7730,12 @@ bash_tips 2024-12-30 + * util: ble/path#remove-glob で * を指定すると後ろまで全て削除してしまう [#D2310] + + これはとんでもない振る舞いである。元々は恐らく * を使うつもりはなかったが、 + 実際のところ例えば WSL2 で /mnt を除外する為に remove-glob PATH '/mnt/*' 等 + を指定するので考慮に入れる必要がある。これは修正するべき。 + * global: avoid raw word splitting [#D2309] 未だ $bytes 等の様に quote されていない箇所があって気になるので、 diff --git a/src/util.sh b/src/util.sh index 0c8d54aa..dfdaf7a7 100644 --- a/src/util.sh +++ b/src/util.sh @@ -1390,18 +1390,33 @@ function ble/path#remove { fi builtin eval -- "$_ble_local_script" } -function ble/path#remove-glob { - [[ $2 ]] || return 1 - local _ble_local_script=' - opts=:${opts//:/::}: - opts=${opts//:$2:} - opts=${opts//::/:} opts=${opts#:} opts=${opts%:}' - _ble_local_script=${_ble_local_script//opts/"$1"} +## @fn ble/path#remove-glob/.impl str pat +## @var[out] ret +function ble/path#remove-glob/.impl { + local IFS=: nocasematch= if shopt -q nocasematch 2>/dev/null; then shopt -u nocasematch - _ble_local_script=$_ble_local_script';shopt -s nocasematch' + nocasematch=1 fi - builtin eval -- "$_ble_local_script" + + local str=$1 pat=$2 paths i + ble/string#split paths : "$str" + for i in "${!paths[@]}"; do + if [[ ${paths[i]} == $pat ]]; then + builtin unset -v 'paths[i]' + fi + done + ret="${paths[*]}" + + if [[ $nocasematch ]]; then + shopt -s nocasematch + fi +} +function ble/path#remove-glob { + [[ $2 ]] || return 1 + [[ $1 == ret ]] || local ret + IFS=: ble/path#remove-glob/.impl "${!1}" "$2" + [[ $1 == ret ]] || builtin eval -- "$1=\$ret" } function ble/path#contains { builtin eval "[[ :\${$1}: == *:\"\$2\":* ]]"