حدد قيمًا فريدة أو مميزة من قائمة في برنامج UNIX Shell النصي

StackOverflow https://stackoverflow.com/questions/618378

سؤال

لدي برنامج نصي ksh يُرجع قائمة طويلة من القيم، مفصولة بسطر جديد، وأريد رؤية القيم الفريدة/المتميزة فقط.فمن الممكن أن تفعل هذا؟

على سبيل المثال، لنفترض أن الإخراج الخاص بي هو لاحقات الملفات في الدليل:

tar
gz
java
gz
java
tar
class
class

أريد أن أرى قائمة مثل:

tar
gz
java
class
هل كانت مفيدة؟

المحلول

قد ترغب في إلقاء نظرة على uniq و sort التطبيقات.

./yourscript.ksh | sort | uniq

(لمعلوماتك، نعم، هذا النوع ضروري في سطر الأوامر هذا، uniq يقوم فقط بإزالة الخطوط المكررة التي تقع مباشرة بعد بعضها البعض)

يحرر:

خلافا لما نشره آرون ديجولا المتعلق ب uniqخيارات سطر الأوامر:

نظرا للمدخلات التالية:

class
jar
jar
jar
bin
bin
java

uniq سيتم إخراج جميع الأسطر مرة واحدة بالضبط:

class
jar
bin
java

uniq -d سوف يقوم بإخراج كافة الأسطر التي تظهر أكثر من مرة، وسوف يقوم بطباعتها مرة واحدة:

jar
bin

uniq -u سوف يقوم بإخراج كافة الأسطر التي تظهر مرة واحدة بالضبط، وسوف يقوم بطباعتها مرة واحدة:

class
java

نصائح أخرى

لمجموعات البيانات الكبيرة حيث الفرز قد لا يكون مرغوبا فيه، يمكنك أيضا استخدام البرنامج النصي بيرل التالية:

./yourscript.ksh | perl -ne 'if (!defined $x{$_}) { print $_; $x{$_} = 1; }'

وهذا في الأساس مجرد يتذكر كل خط الانتاج بحيث لا إخراجه مرة أخرى.

ولديها ميزة على حل "sort | uniq" في أنه لا يوجد الفرز المطلوبة في خط الهجوم.

مع zsh يمكنك القيام بذلك:

zsh-5.0.0[t]% cat infile 
tar
more than one word
gz
java
gz
java
tar
class
class
zsh-5.0.0[t]% print -l "${(fu)$(<infile)}"
tar
more than one word
gz
java
class

وأو يمكنك استخدام AWK:

zsh-4.3.9[t]% awk '!_[$0]++' infile    
tar
more than one word
gz
java
class

والأنابيب من خلال sort وuniq. هذا يزيل كل التكرارات.

وuniq -d يعطي فقط التكرارات، uniq -u يعطي فقط تلك فريدة (يجرد مكررة).

ومع AWK يمكنك القيام به، أجد أنه أسرع من نوع

 ./yourscript.ksh | awk '!a[$0]++'

وفريدة من نوعها، كما طلب منها، (ولكن غير مصنفة)؛
يستخدم موارد النظام أقل أقل من ~ 70 عنصرا (كما تم اختبارها مع مرور الوقت)؛
كتب لاتخاذ مدخلات من ستدين،
(أو تعديل وتدرج في نص برمجي آخر):
(باش)

bag2set () {
    # Reduce a_bag to a_set.
    local -i i j n=${#a_bag[@]}
    for ((i=0; i < n; i++)); do
        if [[ -n ${a_bag[i]} ]]; then
            a_set[i]=${a_bag[i]}
            a_bag[i]=$'\0'
            for ((j=i+1; j < n; j++)); do
                [[ ${a_set[i]} == ${a_bag[j]} ]] && a_bag[j]=$'\0'
            done
        fi
    done
}
declare -a a_bag=() a_set=()
stdin="$(</dev/stdin)"
declare -i i=0
for e in $stdin; do
    a_bag[i]=$e
    i=$i+1
done
bag2set
echo "${a_set[@]}"
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top