我需要运行一个脚本,使用readarray -d / -t
将文件路径分割成数组,但是目标系统的readarray
不支持-d
选项(bash版本4.2.46)
因为我不知道readarray -d / -t
的确切行为,所以我很难为它写一个变通方法。似乎不可能用IFS=/ read -a
替换它,因为包含控制字符的文件名会破坏它,如下所示:IFS=/ read -a arr < <(echo /home/fravadona/$'n'/underneath)
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
?
filepath=/home/fravadona/$'n'/underneath
unset arr; declare -a arr
prefix="${filepath%%/*}"
suffix="${filepath#*/}"
until [ "X$prefix" == "X$suffix" ]
do
arr+=( "$prefix" )
prefix="${suffix%%/*}"
suffix="${suffix#*/}"
done
arr+=( "$prefix" )
希望这能达到你的期望:
filepath=/home/fravadona/$'n'/underneath
IFS=/ read -d "" -r -a arr < <(printf "%s" "$filepath")
declare -p arr
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]=$'fravadonan')
declare -a arr=([0]="" [1]="home" [2]="fravadona" [3]=$'n')
declare -a arr=([0]="" [1]="home" [2]="fravadona" [3]=$'n' [4]=$'underneathn')
以下代码是否正确地模拟了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]=$'fravadonan')
declare -a arr=([0]="" [1]="home" [2]="fravadona" [3]=$'n')
declare -a arr=([0]="" [1]="home" [2]="fravadona" [3]=$'n' [4]=$'underneathn')
所以它是一样的,所以经过一些调整后的答案是肯定的。
很奇怪,你总是使用[ X
的技巧-旧的bug早就消失了,无论如何==
是[
的非标准…在bash中,只需使用[[ "$prefix" == "$suffix" ]]
相关:需要替代readarray/mapfile在旧版本的Bash脚本。我会选择零字节,比如:
f() {
arr=();
while IFS= read -d '' -r elem || [[ -n "$elem" ]]; do
arr+=("$elem")
done < <(
tr '/' ' '
)
}
用
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 $'fravadonan')
arr=('' home fravadona $'n')
arr=('' home fravadona $'n' $'underneathn' )
请注意,每个数组都有一个空的第一个元素,对应于第一个"行",删除了末尾的分隔符。
特别注意,每个结果的最后一个元素都包含一个尾随换行符。这是因为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
case $filepath in
*/) suffix=$filepath;;
*) suffix=${filepath}/;;
esac
while [[ -n "$suffix" ]]; do
arr+=(${suffix%%/*})
suffix=${suffix#*/}
done