有什么方法可以加快下面的shell腳本嗎?我每天要花40分鐘來更新大約15萬個檔案。當然,考慮到要創建和更新的檔案量,這可能是可以接受的。我不否認這一點。但是,如果有更有效的方法來寫這個,或者完全重寫邏輯,我很愿意接受。請給我一些幫助
。 #!/bin/bash
DATA_FILE_SOURCE="<path_to_source_data/${1}"/span>
DATA_FILE_DEST="<path_to_dest>"
for fname in $(ls -1 "${DATA_FILE_SOURCE}"/span>)
do
for line in $(cat "${DATA_FILE_SOURCE}"/span>/"${fname}"/span>)
do
FILE_TO_WRITE_TO=$(echo "${line}" | awk -F',' '{print 1" 。 "2".daily.csv"}')
CONTENT_TO_WRITE=$(echo "${line}"/span> | cut -d, -f3-)
if [[ ! -f "${DATA_FILE_DEST}"/"${FILE_TO_WRITE_TO}" ]]
then
echo "${CONTENT_TO_WRITE}" > > "${DATA_FILE_DEST}"/span>/"${FILE_TO_WRITE_TO}"
else
if ! grep -Fxq "${CONTENT_TO_WRITE}"/span> "${DATA_FILE_DEST}"/span>/"${FILE_TO_WRITE_TO}"/span>
然后
sed -i "/${1}d" "${DATA_FILE_DEST}"/span>/"${FILE_TO_WRITE_TO}"/span>
"${DATA_FILE_DEST}"/span>/"${FILE_TO_WRITE_TO}"
echo "${CONTENT_TO_WRITE}" > > "${DATA_FILE_DEST}"/span>/"${FILE_TO_WRITE_TO}"
fi
fi
done
done done
uj5u.com熱心網友回復:
你發布的腳本中仍有一些地方不清楚,比如sed命令。雖然我在重寫時采用了更理智的做法,并且減少了外部呼叫,但巫師應該真的能加快它的速度。
#!/usr/bin/env sh
DATA_FILE_SOURCE="<path_to_source_data/$1"/span>。
DATA_FILE_DEST="<path_to_dest>"
for fname in "$DATA_FILE_SOURCE/"*; do>
while IFS=, read -r a b content || [ "$a"/span> ]; do
destfile="$DATA_FILE_DEST/$a.$b.day.csv"
if grep -Fxq "$content"/span> "$destfile"/span>。然后
sed -i "/$1/d"/span> "$destfile"
fi
printf '%s
' "$content" >> "$destfile"
done < "$fname"
done
uj5u.com熱心網友回復:
使之平行(盡可能多)。
#!/bin/bash set -e -o pipefail declare -ir MAX_PARALLELISM=20 # pick a limit。 declare -i pid declare -a pids # ... for fname in "${DATA_FILE_SOURCE}/"*; do> if ((${#pids[@]} >= MAX_PARALLELISM)); then wait -p pid -n || echo "${pids[pid]} failed with ${? }" 1>&2 unset 'pids[pid]'/span> fi while IFS= read -r line; do FILE_TO_WRITE_TO="..."/span> # ... done < "${fname}" & # forking here pids[$!]="${fname}" done for pid in "${!pids[@]}"; do 等待 -n "$((pid))" || echo "${pids[pid]} failed with ${? }" 1>&2 done下面是一個可直接運行的骨架,顯示了上面的線束是如何作業的(有36個專案要處理,最多有20個并行行程):
#!/bin/bash set -e -o pipefail declare -ir MAX_PARALLELISM=20 # pick a limit。 declare -i pid declare -a pids do_something_and_maybe_fail() { sleep $((RANDOM % 10) return $((RANDOM % 2 * 5) } for fname in some_name_{a..f}{0..5}.txt; do # 36項 if ((${#pids[@]} >= MAX_PARALLELISM)); then wait -p pid -n || echo "${pids[pid]} failed with ${? }" 1>&2 unset 'pids[pid]'/span> fi do_something_and_maybe_fail & # forking here pids[$!]="${fname}" echo "${#pids[@]}運行" 1>& 2 done for pid in "${!pids[@]}"; do 等待 -n "$((pid))" || echo "${pids[pid]} failed with ${? }" 1>&2 done在處理每一行的單行時,嚴格避免外部行程(如
awk、grep和cut)。fork()相比之下,效率極其低下:- 在整個輸入檔案上運行一個單一的
awk/grep/cut行程(為了在bash中更容易處理,一次性預處理所有行)并將整個輸出送入(例如)一個bash回圈。 - 在可行的情況下使用Bash擴展,例如
"${line/,/.}"和其他來自man bash頁面的EXPANSION部分的技巧,而不需要fork()任何進一步的行程。 題外話:
ls -1是不必要的。首先,ls不會寫多列,除非輸出是一個終端,所以一個普通的ls就可以了。其次,bash擴展通常是一個更干凈、更有效的選擇。(你可以使用nullglob來正確處理空目錄/"不匹配 "的情況。)在
cat的輸出上進行回圈是一個(不太常見的)無用的使用cat的情況。將檔案送入bash中的一個回圈,而不是逐行讀取。(這也為你提供了更多的行格式的靈活性。)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/308002.html
標籤:
