繁体   English   中英

bash“readarray -d / -t”的确切行为是什么?

[英]What is the exact behaviour of bash "readarray -d / -t"?

我需要运行一个使用readarray -d / -t将文件路径拆分为数组的脚本,但目标系统的readarray不支持-d选项(bash 版本 4.2.46)

由于我不知道readarray -d / -t的确切行为,因此我很难为它编写解决方法。 它不似乎可以用来替换IFS=/ read -a因为包含控制字符的文件名会打破它,如下所示:

filepath=/home/fravadona/$'\n'/underneath
IFS=/ read -a arr < <(echo "$filepath")
declare -p arr
# OUTPUT: declare -a arr='([0]="" [1]="home" [2]="fravadona")'

所以,我的第一个问题是,预期的结果是什么:

readarray -d / -t arr < <(echo /home/fravadona)
readarray -d / -t arr < <(echo /home/fravadona/)
readarray -d / -t arr < <(echo /home/fravadona/$'\n'/underneath)

最后,以下代码是否正确模拟了readline -d / -t

unset arr; declare -a arr

prefix="${filepath%%/*}"
suffix="${filepath#*/}"

until [ "X$prefix" == "X$suffix" ]
do
    arr+=( "$prefix" )
    prefix="${suffix%%/*}"
    suffix="${suffix#*/}"
done

arr+=( "$prefix" )

bash“readarray -d / -t”的确切行为是什么?

读取所有输入。 /上拆分它。 删除/ 分配给数组。

什么是预期的结果:

以下脚本:

readarray -d / -t arr < <(echo /home/fravadona)
declare -p arr
readarray -d / -t arr < <(echo /home/fravadona/)
declare -p arr
readarray -d / -t arr < <(echo /home/fravadona/$'\n'/underneath)
declare -p arr

输出:

declare -a arr=([0]="" [1]="home" [2]=$'fravadona\n')
declare -a arr=([0]="" [1]="home" [2]="fravadona" [3]=$'\n')
declare -a arr=([0]="" [1]="home" [2]="fravadona" [3]=$'\n' [4]=$'underneath\n')

以下代码是否正确模拟了 readline -d / -t?

您的代码不会从 stdin 读取,因此它不会模拟readline 您似乎假设输入存储在某个变量中。

以下代码:

f() {
    IFS= read -d '' -r filepath
    arr=()

    prefix="${filepath%%/*}"
    suffix="${filepath#*/}"

    until [ "X$prefix" == "X$suffix" ]
    do
        arr+=( "$prefix" )
        prefix="${suffix%%/*}"
        suffix="${suffix#*/}"
    done

    arr+=( "$prefix" )
}
f < <(echo /home/fravadona)
declare -p arr
f < <(echo /home/fravadona/)
declare -p arr
f < <(echo /home/fravadona/$'\n'/underneath)
declare -p arr

输出:

declare -a arr=([0]="" [1]="home" [2]=$'fravadona\n')
declare -a arr=([0]="" [1]="home" [2]="fravadona" [3]=$'\n')
declare -a arr=([0]="" [1]="home" [2]="fravadona" [3]=$'\n' [4]=$'underneath\n')

所以它是一样的,所以经过一些调整后的答案是肯定的。

这是奇怪的是,你使用[ X招nawadays -老臭虫早已不复存在了,反正==是非标准的[ ..在bash,只是使用[[ "$prefix" == "$suffix" ]]

相关: 需要替代 readarray/mapfile 用于旧版本 Bash 上的脚本 我会使用零字节,例如:

f() {
   arr=();
   while IFS= read -d '' -r elem || [[ -n "$elem" ]]; do
         arr+=("$elem")
   done < <(
         tr '/' '\0'
   )
}

[似乎] 不可能用IFS=/ read -a替换它,因为包含控制字符的文件名会破坏它,

具体来说,包含换行符的文件名会破坏它。 其他控制字符应该不是问题。

所以,我的第一个问题是,预期的结果是什么:

 readarray -d / -t arr < <(echo /home/fravadona) readarray -d / -t arr < <(echo /home/fravadona/) readarray -d / -t arr < <(echo /home/fravadona/$'\\n'/underneath)

它们分别相当于

arr=('' home $'fravadona\n')
arr=('' home fravadona $'\n')
arr=('' home fravadona $'\n' $'underneath\n' )

请注意,每个数组都有一个空的第一个元素,对应于第一个“行”,并删除了尾随定界符。

并特别注意每个结果的最后一个元素都包含一个尾随换行符。 这是因为echo默认以 1 结束其输出,并且您正在指示readarray使用不同的行分隔符。

那么,您可能也对这些感兴趣......

readarray -d / -t arr < <(echo -n /home/fravadona)
readarray -d / -t arr < <(echo -n /home/fravadona/)
readarray -d / -t arr < <(echo -n /home/fravadona/$'\n'/underneath)

...产生与...相同的结果

arr=('' home fravadona)
arr=('' home fravadona)
arr=('' home fravadona $'\n' underneath)

最后,以下代码是否正确模拟了 readline -d / -t?

 unset arr; declare -a arr prefix="${filepath%%/*}" suffix="${filepath#*/}" until [ "X$prefix" == "X$suffix" ] do arr+=( "$prefix" ) prefix="${suffix%%/*}" suffix="${suffix#*/}" done arr+=( "$prefix" )

不,它没有,至少是因为条件[ "X$prefix" == "X$suffix" ]是错误的。 例如,如果$filepathfoo/foo则不会执行循环的迭代,并且arr的最终值将只包含一个元素,而不是两个。 或者,如果$filepath/foo/bar/bar则最终结果只有两个元素,而不是三个。

这样会更好:

unset arr
declare -a arr
suffix=$filepath

while [[ -n "$suffix" ]]; do
  arr+=(${suffix%%/*})
  suffix=${suffix#*/}
done

希望这会达到您的预期:

filepath=/home/fravadona/$'\n'/underneath
IFS=/ read -d "" -r -a arr < <(printf "%s" "$filepath")
declare -p arr

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM