shell - نظام - جميع اوامر الاختراق kali linux




كيف يمكن أن أقوم بخلط خطوط ملف نصي على سطر أوامر Unix أو في برنامج نصي shell؟ (13)

أرغب في خلط أسطر الملف النصي بشكل عشوائي وإنشاء ملف جديد. قد يحتوي الملف على عدة آلاف من الأسطر.

كيف يمكنني أن أفعل ذلك مع القط ، awk ، قطع ، وما إلى ذلك؟


أستخدم نصًا برلوسًا صغيرًا ، أسميه "unsort":

#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);

لديّ أيضًا إصدارًا مفصولًا بـ NULL ، يُطلق عليه "unsort0" ... مفيد للاستخدام مع البحث عن -print0 وما إلى ذلك.

ملاحظة: صُوِّرت 'شوف' أيضًا ، لم يكن لدي أي فكرة عن وجودها في النواة هذه الأيام ... ما سبق قد يكون مفيدًا إذا لم يكن لديك نظام "شوف".


إذا كنت قد ركبت سكالا ، فإليك خطًا واحدًا لخلط الإدخال:

ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'

بطانة واحدة لبيثون تستند إلى إجابة scai ، ولكن أ) يأخذ stdin ، ب) يجعل النتيجة قابلة للتكرار مع البذور ، ج) يختار 200 فقط من جميع الخطوط.

$ cat file | python -c "import random, sys; 
  random.seed(100); print ''.join(random.sample(sys.stdin.readlines(), 200))," \
  > 200lines.txt

بطانة واحدة للثعبان:

python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile

ولطباعة خط عشوائي واحد فقط:

python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile

ولكن انظر هذا المنصب random.shuffle() بيثون random.shuffle() . random.shuffle() . لن تعمل بشكل جيد مع العديد من العناصر (أكثر من 2080).


تتميز وظيفة bash هذه بالحد الأدنى من التبعية (فقط الفرز والبس):

shuf() {
while read -r x;do
    echo $RANDOM$'\x1f'$x
done | sort |
while IFS=$'\x1f' read -r x y;do
    echo $y
done
}

تكمل هذه الإجابة العديد من الإجابات الموجودة الكبيرة بالطرق التالية:

  • يتم حزم الإجابات الموجودة في وظائف shell مرنة :

    • لا تأخذ الوظائف المدخلات stdin فقط ، ولكن بدلا من ذلك أيضا أسماء الملفات
    • تأخذ الوظائف خطوات إضافية للتعامل مع SIGPIPE بالطريقة المعتادة (الإنهاء الهادئ مع رمز الخروج 141 ) ، بدلاً من كسر الضوضاء. هذا مهم عند توجيه الإخراج الوظيفي إلى أنبوب مغلق في وقت مبكر ، كما هو الحال عند توجيه الأنبوب إلى head .
  • يتم إجراء مقارنة الأداء .

  • وظيفة متوافقة مع POSIX تعتمد على awk ، sort ، cut ، مقتبسة من إجابة OP الخاصة :
shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print rand(), $0}' "[email protected]" |
               sort -k1,1n | cut -d ' ' -f2-; }
  • بيرل الوظيفة القائمة - تكيفت من إجابة Moonyoung كانج :
shuf() { perl -MList::Util=shuffle -e 'print shuffle(<>);' "[email protected]"; }
  • وظيفة تستند إلى بايثون ، مقتبسة من إجابة scai :
shuf() { python -c '
import sys, random, fileinput; from signal import signal, SIGPIPE, SIG_DFL;    
signal(SIGPIPE, SIG_DFL); lines=[line for line in fileinput.input()];   
random.shuffle(lines); sys.stdout.write("".join(lines))
' "[email protected]"; }
  • دالة تستند إلى روبي ، مقتبسة من إجابة hoffmanc :
shuf() { ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
                     puts ARGF.readlines.shuffle' "[email protected]"; }

مقارنة الأداء:

ملاحظة: تم الحصول على هذه الأرقام في جهاز iMac في أواخر عام 2012 باستخدام معالج Intel Core i5 بسرعة 3.2 جيجاهرتز وبرنامج Fusion Drive ، الذي يشغل OSX 10.10.3. في حين أن التوقيت يختلف مع نظام التشغيل المستخدم ، مواصفات الجهاز ، تطبيق awk المستخدم (على سبيل المثال ، الإصدار awk BSD المستخدم في OSX عادة ما يكون أبطأ من GNU awk وخاصة mawk ) ، وهذا يجب أن يوفر إحساسًا عامًا بالأداء النسبي .

ملف الإدخال هو ملف بمليون خط يتم إنتاجه باستخدام seq -f 'line %.0f' 1000000 .
يتم سرد الأوقات بترتيب تصاعدي (الأسرع أولاً):

  • shuf
    • 0.090s
  • روبي 2.0.0
    • 0.289s
  • بيرل 5.18.2
    • 0.589s
  • الثعبان
    • 1.342s مع Python 2.7.6؛ 2.407s (!) مع Python 3.4.2
  • awk + sort + cut
    • 3.003s مع BSD awk ؛ 2.388s مع GNU awk (4.1.1) ؛ 1.811s with mawk (1.3.4)؛

لمزيد من المقارنة ، فإن الحلول لا يتم تعبئتها كوظائف أعلاه:

  • sort -R (ليس خلطًا حقيقيًا إذا كان هناك خطوط إدخال مكررة)
    • 10.661s - يبدو أن تخصيص المزيد من الذاكرة لا يحدث فرقًا
  • سكالا
    • 24.229s
  • حلقات bash + sort
    • 32.593s

الاستنتاجات :

  • استخدم shuf ، إذا استطعت - إنه الأسرع حتى الآن.
  • روبي يفعل جيدا ، تليها بيرل .
  • بايثون أبطأ بشكل ملحوظ من روبي و بيرل ، و بمقارنة إصدارات بايثون ، 2.7.6 هي أسرع قليلا من 3.4.1
  • استخدم مجموعة التحرير awk + sort + المتوافق مع POSIX كملاذ أخير ؛ التي تستخدم فيها تطبيق awk ( mawk أسرع من GNU awk ، BSD awk هي الأبطأ).
  • البقاء بعيدا عن sort -R ، bash الحلقات ، سكالا.

شكل awk آخر:

#!/usr/bin/awk -f
# usage:
# awk -f randomize_lines.awk lines.txt
# usage after "chmod +x randomize_lines.awk":
# randomize_lines.awk lines.txt

BEGIN {
  FS = "\n";
  srand();
}

{
  lines[ rand()] = $0;
}

END {
  for( k in lines ){
    print lines[k];
  }
}

في ما يلي أول محاولة سهلة على المبرمج ولكن من الصعب على وحدة المعالجة المركزية (CPU) التي تضيف رقمًا عشوائيًا لكل سطر ، وتقوم بفرزها ثم تسقط الرقم العشوائي من كل سطر. في الواقع ، يتم فرز الخطوط بشكل عشوائي:

cat myfile | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled

لدينا مجموعة للقيام بهذه المهمة:

sudo apt-get install randomize-lines

مثال:

إنشاء قائمة مرتبة من الأرقام وحفظها على 1000.txt:

seq 1000 > 1000.txt

لخلطها ، ببساطة استخدام

rl 1000.txt

لم يرد ذكره بعد:

  1. استخدام unsort . بناء الجملة (موجهة إلى حد ما قائمة التشغيل):

    unsort [-hvrpncmMsz0l] [--help] [--version] [--random] [--heuristic]
           [--identity] [--filenames[=profile]] [--separator sep] [--concatenate] 
           [--merge] [--merge-random] [--seed integer] [--zero-terminated] [--null] 
           [--linefeed] [file ...]
    
  2. يمكن أن msort ، ولكن عادة ما يكون overkill:

    seq 10 | msort -jq -b -l -n 1 -c r
    

وظيفة بسيطة مبنية على awk ستقوم بهذه المهمة:

shuffle() { 
    awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, $0;}' | sort -n | cut -c8-
}

الاستعمال:

any_command | shuffle

يجب أن يعمل هذا على أي UNIX تقريبًا. تم اختباره على Linux و Solaris و HP-UX.

تحديث:

لاحظ أن %06d الأصفار البادئة ( %06d ) و rand() تجعلها تعمل بشكل صحيح أيضًا على أنظمة لا يفهم فيها sort الأرقام. ويمكن فرزها عن طريق النظام المعجمى (المعروف أيضا باسم مقارنة السلسلة العادية).


وهنا سكربت awk

awk 'BEGIN{srand() }
{ lines[++d]=$0 }
END{
    while (1){
    if (e==d) {break}
        RANDOM = int(1 + rand() * d)
        if ( RANDOM in lines  ){
            print lines[RANDOM]
            delete lines[RANDOM]
            ++e
        }
    }
}' file

انتاج

$ cat file
1
2
3
4
5
6
7
8
9
10

$ ./shell.sh
7
5
10
9
6
8
2
1
3
4

يمكنك استخدام shuf . على بعض الأنظمة على الأقل (لا يبدو أن في POSIX).

كما أشار جليفديف: قد يكون sort -R خيارًا أيضًا. على بعض النظم على الأقل ؛ حسنا ، يمكنك الحصول على الصورة. وقد أشير إلى أن هذا sort -R لا sort -R الواقع ، ولكن بدلا من ذلك فرز العناصر وفقا لقيمة التجزئة الخاصة بهم.

[ملاحظة المحرر: sort -R تقريبًا تقريبًا ، باستثناء أن الأسطر المكررة / مفاتيح الفرز تنتهي دائمًا بجانب بعضها البعض . وبعبارة أخرى: فقط مع خطوط الإدخال / المفاتيح فريدة من نوعها هو أنه خلط ورق اللعب الحقيقي. في حين أنه صحيح أن يتم تحديد ترتيب الإخراج بواسطة قيم التجزئة ، تأتي العشوائية من اختيار دالة تجزئة عشوائية - راجع manual .]







shuffle