这是一个简单的脚本,它正在卷曲https://unix.stackexchange.com/并将结果存储到一个数组中,它工作正常。
#!/usr/local/bin/bash
[ -f pgtoscrap ] && { rm pgtoscrap; };
curl -o pgtoscrap https://unix.stackexchange.com/;
declare -a arr;
fileName="pgtoscrap";
exec 10<&0
exec < $fileName
let count=0
while read LINE; do
arr[$count]=$LINE
((count++))
done
exec 0<10 10<&-
但是,每次我运行这个脚本时;我收到错误的文件描述符的一些错误。
./shcrap
./shcrap: line 14: 10: No such file or directory
我想我不太了解如何exec
在循环中正确使用命令。有人可以解释吗?
--mapfile
为 Bash 4 实施后的更新变得更加简单 --
#!/usr/local/bin/bash
## Pass a parameter as e.g. ./linkscrapping.bash https://unix.stackexchange.com/
mapfile -t arr < <(curl -s $1); ## Doing exec stuff with process substitution
regex="<a[[:print:]]*<\/a>"; ELEMENTS=${#arr[@]}; firstline=0;
for((i=0;i<$ELEMENTS;i++)); do
if [[ ${arr[${i}]} =~ $regex ]]; then
[[ $firstline<1 ]] &&
{ echo ${BASH_REMATCH[0]} > scrapped; let firstline=$firstline+1; } ||
{ echo ${BASH_REMATCH[0]} >> scrapped; }
fi
done
pg2scrap="scrapped"; mapfile -t arr2 < <(cat $pg2scrap);
regex="href=[\"\'][0-9a-zA-Z\:\/\.]+"; ELEMENTS2=${#arr2[@]}; line2=0
for ((i=0;i<$ELEMENTS2;i++)); do
if [[ ${arr2[${i}]} =~ $regex ]]; then
[[ $line2<1 ]] &&
{ echo ${BASH_REMATCH[0]#href=\"} > links; (( line2++ )); } ||
{ echo ${BASH_REMATCH[0]#href=\"} >> links; }
fi
done; cat links;
这肯定与您如何关闭之前为标准输入打开的文件描述符有关。使用以下应该没问题
当你这样做时
0<10
,你指示 shell 查找并吞入一个10
在你当前目录中命名的文件的内容,这在这种情况下是没有意义的。bash
您还可以使用另一种形式exec 10>&-
来实现关闭描述符的相同目的。但是就是说,您不需要
exec
在随机文件描述符上使用并读取您的输入,您可以使用进程替换技术以如下bash
形式读取您的输入< <()
exec 10<&0
将文件描述符编号 0 克隆到编号 10,有效地保存原始文件,以便您可以在下一行替换 fd 0 上的文件。要撤消该操作,您需要反转数字,将数字 10 克隆到数字 0,exec 0<&10
(然后使用 关闭 fd 10exec 10<&-
)。另一方面,
exec 0<10
没有&符号只是一个带有文件名的重定向10
。由于您没有这样的文件,因此您会收到错误消息。也就是说,您不需要使用
exec
临时为 while 循环设置重定向。复合命令也可以进行重定向,如下所示:如果您想按原样读取整行,而没有空格或反斜杠影响数据,则需要取消设置
IFS
forread
并使用read -r
. 此外,如果您要追加到数组,则不需要手动跟上索引,您可以直接使用+=
追加到数组:或者使用
mapfile
(readarray
) 而不是像@BlackJack 在评论中提到的手动循环:甚至根本没有临时文件:
(没有
-t
,mapfile
将行终止符留在原处。)