[英]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" ]
是错误的。 例如,如果$filepath
是foo/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.