สมมติว่ามีไดเรกทอรีเก็บไฟล์ข้อมูล 300 ไฟล์ ฉันต้องการสุ่มเลือกไฟล์ 200 ไฟล์และย้ายไปไว้ในไดเรกทอรีอื่น มีวิธีการทำภายใต้ Unix / Linux?
shuf
และhead
(หรือใช้เพียงshuf -n
ควรอ่านหน้าคน ... )
สมมติว่ามีไดเรกทอรีเก็บไฟล์ข้อมูล 300 ไฟล์ ฉันต้องการสุ่มเลือกไฟล์ 200 ไฟล์และย้ายไปไว้ในไดเรกทอรีอื่น มีวิธีการทำภายใต้ Unix / Linux?
shuf
และhead
(หรือใช้เพียงshuf -n
ควรอ่านหน้าคน ... )
คำตอบ:
หากระบบของshuf
คุณคุณสามารถใช้สิ่งนี้ได้อย่างสะดวก (แม้จะจัดการกับชื่อไฟล์ที่น่าเกลียด):
shuf -zen200 source/* | xargs -0 mv -t dest
หากคุณไม่มีshuf
แต่มีสิ่งsort
ที่ต้องทำ-R
สิ่งนี้ควรใช้งานได้:
find source -type f -print0 | sort -Rz | cut -d $'\0' -f-200 | xargs -0 mv -t dest
shuf
ก็ไม่ได้ถูกเรียกtros
เพราะมันตรงกันข้ามกับการเรียงลำดับ)
files=(*)
for (( i=0; i<200; i++ )); do
keys=("${!files[@]}")
rnd=$(( RANDOM % ${#keys[@]} ))
key=${keys[$rnd]}
mv "${files[$key]}" "$otherdir"
unset files[$key]
done
ใส่ชื่อไฟล์ทั้งหมดลงในอาร์เรย์ชื่อ "files" ใน bash:
files=( * )
ขนาดของอาร์เรย์:
echo ${#files[@]}
กำหนด 2/3 ของพวกเขาเป็นขนาดตัวอย่าง:
take=$((2*${#files[@]}/3))
for i in $(seq 1 $take)
do
r=$((RANDOM%${#files[@]}))
echo ${files[r]}
done
นี้จะเลือกรายการที่ซ้ำกันและจะไม่ได้ทดสอบกับชื่อไฟล์ที่มีช่องว่างดังกล่าว
วิธีที่ง่ายที่สุดในการหลีกเลี่ยงการทำซ้ำคือการวนซ้ำไฟล์ทั้งหมดและเลือกแต่ละไฟล์ที่มีโอกาส 2/3 แต่สิ่งนี้จะไม่นำไปสู่ 200 ไฟล์
การดำเนินการนี้จะลบไฟล์หากเลือกจากรายการและปฏิบัติตามข้อกำหนดของคุณ:
#!/bin/bash
files=( * )
# define 2/3 of them as sample size:
take=$((2*${#files[@]}/3))
while (( i < $take ))
do
r=$((RANDOM%${#files[@]}))
f=${files[r]}
if [[ -n $f ]]
then
i=$((i+1))
echo ${files[r]}
unset files[r]
fi
done
$RANDOM
สามารถมีค่า 0 ถึง 32767 เท่านั้นดังนั้นสิ่งนี้จะทำงานไม่ถูกต้องหากคุณมีไฟล์มากกว่า 32768 ไฟล์ นอกจากนี้การดึงข้อมูลจะมีอคติต่อไฟล์แรก
RANDOM % ${#keys[@]}
ในกรณีนี้จะต้องมีการสุ่มทางสถิติที่คุณไม่ควรใช้ พิจารณา:
$RANDOM
มีค่าที่ไม่ซ้ำ 32768ดังนั้นเมื่อเลือกรายการแรกจะมีโอกาส 110/32768 ~ = 0.33569% สำหรับแต่ละองค์ประกอบแรก 68 รายการและ 109/32768 ~ = โอกาส 0.33264% สำหรับแต่ละองค์ประกอบ 232 รายการอื่นที่จะเลือก การเลือกซ้ำหลายครั้งด้วยโอกาสที่แตกต่างกัน แต่เอนเอียงไปที่องค์ประกอบแรกเมื่อใดก็ตาม32768 % ${#keys[@]} -ne 0
ดังนั้นสารประกอบที่ผิดพลาด
สิ่งนี้ควรไม่เอนเอียงและทำงานกับชื่อไฟล์ใด ๆ :
while IFS= read -r -d '' -u 9
do
mv -- "$REPLY" /target/dir
done 9< <(find /source/dir -mindepth 1 -print0 | shuf -n 200 -z)
ทางออกของเควินนั้นยอดเยี่ยม! อย่างอื่นที่ฉันเคยใช้บ่อยเพราะมันง่ายกว่าที่จะจำได้ว่าส่วนบนของหัวของฉันเป็นสิ่งที่ชอบ:
cp `ls | shuf -n 200` destination
หนึ่งซับในทุบตี:
ls original_directory/|sort -R|head -number_of_files_to_move|while read file; do cp "new_directory/"$file test; done
list.files()
...