Webスクレイピングのためのbashループのexecコマンド

Webスクレイピングのためのbashループのexecコマンド

以下は簡単なカールスクリプトです。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ループ内でコマンドを正しく使用する方法をよく理解していないようです。誰かがこれを説明できますか?

- Bash 4を実装したmapfile後、アップデートが簡単になりました -

#!/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;

ベストアンサー1

これは、以前にstdin用に開いたファイル記述子を閉じる方法に関連しているはずです。以下を使うと大丈夫でしょう

exec 10<&- 

これにより、現在のディレクトリに指定されているファイルの内容を0<10見つけて読み取るようにシェルに指示します。10いいえこの文脈では意味があります。

記述子を閉じるのと同じ目的を達成するために、他のフォームを使用することもbashできます。exec 10>&-

しかし、つまり、任意のファイル記述子を使用して入力を読み取る必要はなく、次の形式のプロセスexec置換技術を使用して入力を読み取ることができます。bash< <()

while IFS= read -r line; do
    arr["$count"]="$line"
    ((count++))
done< <(pgtoscrap)

おすすめ記事