ব্যাশে কোনও ডিরেক্টরি থেকে আমি এলোমেলো ফাইলগুলি কীভাবে নির্বাচন করতে পারি?


144

আমার প্রায় 2000 টি ফাইল সহ একটি ডিরেক্টরি রয়েছে। Nবাশ স্ক্রিপ্ট বা পাইপড কমান্ডের একটি তালিকা ব্যবহার করে আমি কীভাবে ফাইলগুলির এলোমেলো নমুনা নির্বাচন করতে পারি ?


1
ইউনিক্স এবং লিনাক্সেও একটি ভাল উত্তর: unix.stackexchange.com/a/38344/24170
নিকানা রেকলাভিক্স


উত্তর:


180

এখানে একটি স্ক্রিপ্ট যা GNU সাজ্টের র্যান্ডম বিকল্প ব্যবহার করে:

ls |sort -R |tail -$N |while read file; do
    # Something involving $file, or you can leave
    # off the while to just get the filenames
done

শীতল, সারণি -আর জানতেন না; আমি আগে বোগোসর্ট ব্যবহার করেছি :
অ্যালেক্স

5
বাছাই করুন: অবৈধ বিকল্প - আরও তথ্যের জন্য 'বাছাই করুন - সহায়তা' চেষ্টা করুন।

2
মনে হয় না যে এগুলির জন্য ফাঁকা স্থান রয়েছে এমন ফাইলগুলির জন্য কাজ করে।
হাউশাল্টার

এটি ফাঁকা স্থানগুলির (পাইপলাইন প্রক্রিয়াগুলি লাইন) সহ ফাইলগুলির জন্য কাজ করা উচিত। এটিতে নতুন লাইনের সাথে নামের জন্য এটি কাজ করে না। কেবল "$file"প্রদর্শিত, প্রদর্শিত না ব্যবহারের জন্য স্পেসগুলি সংবেদনশীল হবে।
ইয়ান ভার্নিয়ার


108

আপনি তার জন্য shuf(জিএনইউ কোর্টিল প্যাকেজ থেকে) ব্যবহার করতে পারেন। কেবল এটিকে ফাইলের নামের একটি তালিকা খাওয়ান এবং এলোমেলো ক্রমানুসারে প্রথম লাইনে ফিরে আসতে বলুন:

ls dirname | shuf -n 1
# probably faster and more flexible:
find dirname -type f | shuf -n 1
# etc..

-n, --head-count=COUNTপছন্দসই লাইনের সংখ্যা ফেরতের জন্য মানটি সামঞ্জস্য করুন । উদাহরণস্বরূপ 5 টি র্যান্ডম ফাইল নামগুলি আপনি ব্যবহার করবেন:

find dirname -type f | shuf -n 5

4
ওপি Nর্যান্ডম ফাইলগুলি নির্বাচন করতে চেয়েছিল , তাই ব্যবহার 1করা কিছুটা বিভ্রান্তিকর।
আইয়ুব

4
আপনার যদি নতুন find dirname -type f -print0 | shuf -zn1
লাইনের

5
আমাকে যদি এলোমেলোভাবে নির্বাচিত ফাইলগুলি অন্য ফোল্ডারে অনুলিপি করতে হয় তবে কী হবে? এই এলোমেলোভাবে নির্বাচিত ফাইলগুলিতে অপারেশন কীভাবে করবেন?
habষভ অগ্রহরি

18

এখানে কয়েকটি সম্ভাবনা রয়েছে যা আউটপুটকে বিশ্লেষণ করে না lsএবং এটি তাদের নামে স্পেস এবং মজার চিহ্ন সহ ফাইলগুলি সম্পর্কিত 100% নিরাপদ। এগুলির সবগুলি randfএলোমেলো ফাইলগুলির একটি তালিকা সহ একটি অ্যারে তৈরি করবে । এই অ্যারে printf '%s\n' "${randf[@]}"প্রয়োজনে সহজেই মুদ্রিত হয় ।

  • এটি সম্ভবত একই ফাইলটিকে বেশ কয়েকবার আউটপুট দেবে Nএবং আগে থেকেই জানা দরকার। এখানে আমি এন = 42 বেছে নিয়েছি।

    a=( * )
    randf=( "${a[RANDOM%${#a[@]}]"{1..42}"}" )

    এই বৈশিষ্ট্যটি খুব ভাল নথিভুক্ত নয়।

  • এন যদি আগে থেকে জানা না যায় তবে আপনি আগের সম্ভাবনাটি পছন্দ করেছেন, আপনি ব্যবহার করতে পারেন eval। তবে এটি মন্দ, এবং অবশ্যই আপনাকে অবশ্যই নিশ্চিত করতে হবে যে Nভালভাবে পরীক্ষা না করে সরাসরি ব্যবহারকারী ইনপুট থেকে আসে না!

    N=42
    a=( * )
    eval randf=( \"\${a[RANDOM%\${#a[@]}]\"\{1..$N\}\"}\" )

    আমি ব্যক্তিগতভাবে অপছন্দ করি evalএবং তাই এই উত্তর!

  • আরও সরল পদ্ধতি (লুপ) ব্যবহার করে একই:

    N=42
    a=( * )
    randf=()
    for((i=0;i<N;++i)); do
        randf+=( "${a[RANDOM%${#a[@]}]}" )
    done
  • আপনি যদি একই ফাইলটি কয়েকবার সম্ভবত না চান:

    N=42
    a=( * )
    randf=()
    for((i=0;i<N && ${#a[@]};++i)); do
        ((j=RANDOM%${#a[@]}))
        randf+=( "${a[j]}" )
        a=( "${a[@]:0:j}" "${a[@]:j+1}" )
    done

নোট । এটি একটি পুরানো পোস্টের দেরী উত্তর, তবে গৃহীত উত্তরগুলি একটি বাহ্যিক পৃষ্ঠায় লিঙ্ক করে যা ভয়ঙ্কর দেখায়অনুশীলন করুন, এবং অন্য উত্তরটি আরও ভাল নয় কারণ এটি এর আউটপুটকেও বিশ্লেষণ করে ls। গৃহীত উত্তরের একটি মন্তব্য লুনাথের একটি দুর্দান্ত উত্তরের দিকে ইঙ্গিত করে যা স্পষ্টতই ভাল অনুশীলন দেখায়, তবে ঠিক ওপিকে উত্তর দেয় না।


প্রথম এবং দ্বিতীয় উত্পাদিত "খারাপ প্রতিস্থাপন"; এটি "{1..42}"অংশটি পিছনে রেখে পছন্দ করে নি "1"। এছাড়াও, $RANDOMশুধুমাত্র 15 বিট এবং পদ্ধতিটি 32767 টিরও বেশি ফাইল থেকে পছন্দ করে কাজ করবে না।
ইয়ান ভার্নিয়ার

13
ls | shuf -n 10 # ten random files

1
আপনার ফলাফলের উপর নির্ভর করা উচিত নয় ls। উদাহরণস্বরূপ যদি কোনও ফাইলনামে নতুন লাইন থাকে তবে এটি কাজ করবে না।
bfontaine

3
@fontaine আপনি ফাইলের নামগুলিতে নিউলাইন দ্বারা ভুতুড়ে বলে মনে হচ্ছে :)। এগুলি কি আসলেই সাধারণ? অন্য কথায়, এমন কোনও সরঞ্জাম রয়েছে যা তাদের নামে নতুন লাইনের সাথে ফাইল তৈরি করে? ব্যবহারকারী হিসাবে যেহেতু এ জাতীয় ফাইলের নাম তৈরি করা খুব কঠিন। ইন্টারনেট থেকে আসা ফাইলগুলির জন্য একই
সিপরিয়ান টমোইগা

3
@ সিপ্রিয়ানটোমিয়াগা এটি আপনার পেতে পারে এমন সমস্যাগুলির একটি উদাহরণ। lsআপনাকে "পরিষ্কার" ফাইলের নাম দেওয়ার গ্যারান্টি নেই যাতে আপনার পিরিয়ডের উপর নির্ভর করা উচিত নয়। এই বিষয়গুলি বিরল বা অস্বাভাবিক এই বিষয়টি সমস্যাটি পরিবর্তন করে না; বিশেষত প্রদত্ত এর জন্য আরও ভাল সমাধান রয়েছে।
bfontaine

lsডিরেক্টরি এবং ফাঁকা লাইন অন্তর্ভুক্ত থাকতে পারে। আমি find . -type f | shuf -n10পরিবর্তে এর মতো কিছু প্রস্তাব করব ।
চের্ড্ট

9

এলএস পার্স করা এড়াতে5 এলোমেলো ফাইল নির্বাচন করার জন্য একটি সহজ সমাধান । এটি স্পেস, নিউলাইন এবং অন্যান্য বিশেষ অক্ষরযুক্ত ফাইলগুলির সাথেও কাজ করে:

shuf -ezn 5 * | xargs -0 -n1 echo

echoআপনি যে ফাইলগুলি ফাইলের জন্য কার্যকর করতে চান তা দিয়ে প্রতিস্থাপন করুন ।


1
ভাল, পাইপ + readপার্সিংয়ের মতো একই সমস্যা নেই ls? যথা, এটি লাইনে এক এক করে পড়ে, সুতরাং এটি তাদের নামে নতুন লাইনের ফাইলগুলির জন্য কাজ করে না
Ciprian Tomoiagă

3
তুমি ঠিক. আমার পূর্ববর্তী সমাধানটি নিউলাইনযুক্ত ফাইলের নামগুলির জন্য কাজ করে না এবং সম্ভবত কিছু বিশেষ অক্ষর সহ অন্যদেরও বিরতি দেয়। আমি আমার উত্তরটি নতুন লাইনের পরিবর্তে নাল-সমাপ্তি ব্যবহার করতে আপডেট করেছি।
স্কাই

4

যদি আপনি পাইথন ইনস্টল করেন (পাইথন 2 বা পাইথন 3 এর সাথে কাজ করে):

একটি ফাইল নির্বাচন করতে (বা একটি স্বেচ্ছাচারিত কমান্ড থেকে লাইন), ব্যবহার করুন

ls -1 | python -c "import sys; import random; print(random.choice(sys.stdin.readlines()).rstrip())"

Nফাইল / লাইন নির্বাচন করতে, ব্যবহার করুন (নোটটি Nকমান্ডের শেষে রয়েছে, এটি একটি সংখ্যার মাধ্যমে প্রতিস্থাপন করুন)

ls -1 | python -c "import sys; import random; print(''.join(random.sample(sys.stdin.readlines(), int(sys.argv[1]))).rstrip())" N

আপনার ফাইলনামে নতুন লাইন থাকলে এটি কাজ করে না।
bfontaine

4

এটি @ gniourf_gniourf এর দেরী জবাবের পরে একটি প্রতিক্রিয়া, যা আমি সবেমাত্র উচ্চারণ করেছি কারণ এটি দ্বিগুণ হয়ে এখন পর্যন্ত সেরা উত্তর। (একবার এড়ানোর জন্য evalএবং একবার নিরাপদ ফাইল নাম হ্যান্ডলিংয়ের জন্য))

তবে এই উত্তরটি "খুব ভাল ডকুমেন্টেড নয়" বৈশিষ্ট্য (গুলি) আনট্যাগল করতে কয়েক মিনিট সময় নিয়েছে। আপনার বাশ দক্ষতা যদি যথেষ্ট শক্ত হয় তবে আপনি কীভাবে এটি কাজ করে তা তাত্ক্ষণিকভাবে দেখেছিলেন, তবে এই মন্তব্যটি এড়িয়ে যান। তবে আমি তা করি নি, এবং এটির শৃঙ্খলাবদ্ধ না করে আমি মনে করি এটি ব্যাখ্যা করার উপযুক্ত।

বৈশিষ্ট্য # 1 হ'ল শেলের নিজস্ব ফাইল গ্লোববিং। a=(*)একটি অ্যারে তৈরি করে $a, যার সদস্যরা বর্তমান ডিরেক্টরিতে থাকা ফাইলগুলি। ফাইল ফাইলের সমস্ত অদ্ভুততা বোঝে বাশ, সুতরাং সেই তালিকাটি সঠিক, নিশ্চিত পলায়নের গ্যারান্টিযুক্ত, ইত্যাদি পাঠ্য ফাইলের নামগুলি সঠিকভাবে পার্স করার বিষয়ে চিন্তা করার দরকার নেই ls

বৈশিষ্ট্য # 2 হ'ল অ্যারেগুলির জন্য বাশ প্যারামিটার বিস্তৃতি , যার মধ্যে একটির অন্যের মধ্যে বাসা বাঁধে। এটি দিয়ে শুরু হয় , যা দৈর্ঘ্যে প্রসারিত হয় ।${#ARRAY[@]}$ARRAY

সেই সম্প্রসারণটি অ্যারে সাবস্ক্রিপ্ট করার জন্য ব্যবহৃত হয়। 1 এবং N এর মধ্যে একটি এলোমেলো সংখ্যা খুঁজে পাওয়ার মানক উপায়টি হল র্যান্ডম সংখ্যার মডুলো এন এর মান নেওয়া take আমরা 0 এবং আমাদের অ্যারের দৈর্ঘ্যের মধ্যে একটি এলোমেলো সংখ্যা চাই। স্পষ্টতার জন্য দুটি পংক্তিতে বিভক্ত পদ্ধতিটি এখানে:

LENGTH=${#ARRAY[@]}
RANDOM=${a[RANDOM%$LENGTH]}

কিন্তু এই সমাধানটি এটি একটি একক লাইনে করে, অপ্রয়োজনীয় ভেরিয়েবল অ্যাসাইনমেন্টটি সরিয়ে দেয়।

বৈশিষ্ট্য # 3 হ'ল ব্যাশ বন্ধনী সম্প্রসারণ , যদিও আমাকে স্বীকার করতে হবে আমি এটি পুরোপুরি বুঝতে পারি না। বন্ধনী সম্প্রসারণ উদাহরণস্বরূপ ব্যবহার করা হয়, 25 নামে ফাইলগুলির একটি তালিকা তৈরি করতে filename1.txt, filename2.txtইত্যাদি: echo "filename"{1..25}".txt"

উপরের সাবশেলের অভ্যন্তরের অভিব্যক্তি "${a[RANDOM%${#a[@]}]"{1..42}"}", 42 টি পৃথক বিস্তৃতি তৈরি করতে সেই কৌশলটি ব্যবহার করে। ধনুর্বন্ধনী প্রসারণটি এবং এর মধ্যে একক অঙ্ক ]রাখে }, যা প্রথমে আমি ভেবেছিলাম অ্যারে সাবস্ক্রিপশন করছিলাম, তবে যদি তা হয় তবে এটির আগে একটি কোলন থাকবে। (এটি অ্যারেতে এলোমেলো জায়গা থেকে একটানা 42 টি আইটেম ফিরে আসত, যা অ্যারে থেকে 42 টি এলোমেলো আইটেম ফেরত দেওয়ার মত নয়) আমি মনে করি এটি শেলটি 42 বার প্রসারিত করে চলেছে, এরপরে ফিরে আসবে অ্যারে থেকে 42 এলোমেলো আইটেম। (তবে কেউ যদি আরও পুরোপুরি ব্যাখ্যা করতে পারে তবে আমি এটি শুনতে পছন্দ করব))

N কে হার্ডকোডিং (42 থেকে 42) করার কারণ হ'ল চলক প্রসারণের আগে ব্রেস সম্প্রসারণ ঘটে।

পরিশেষে, আপনি যদি একটি ডিরেক্টরি শ্রেণিবিন্যাসের জন্য এটি পুনরাবৃত্তভাবে করতে চান তবে এখানে ফিচার # 4 's

shopt -s globstar
a=( ** )

এটি শেল বিকল্পটি সক্রিয় করে যা **পুনরাবৃত্তির সাথে মেলে। এখন আপনার $aঅ্যারেতে সম্পূর্ণ শ্রেণিবিন্যাসের প্রতিটি ফাইল রয়েছে।


2

আপনার ফোল্ডারে যদি আরও ফাইল থাকে তবে আপনি ইউনিক্স স্ট্যাকেক্সচেঞ্জে পাওয়া নীচের পাইপযুক্ত কমান্ডটি ব্যবহার করতে পারেন ।

find /some/dir/ -type f -print0 | xargs -0 shuf -e -n 8 -z | xargs -0 cp -vt /target/dir/

এখানে আমি ফাইল কপি করতে চেয়েছিলেন, কিন্তু যদি আপনি ফাইল স্থানান্তর করতে চান বা কিছু অন্য না, শুধু গত কমান্ড আমি কোথায় ব্যবহার করেছেন পরিবর্তন cp


1

এই একমাত্র স্ক্রিপ্ট আমি ম্যাকওএসে ব্যাশ দিয়ে সুন্দর খেলতে পারি। আমি নিম্নলিখিত দুটি লিঙ্ক থেকে স্নিপেট একত্রিত এবং সম্পাদনা করেছি:

ls কমান্ড: আমি প্রতি ফাইলটিতে একটি পুনরাবৃত্ত পূর্ণ-পাথ তালিকা পেতে পারি?

http://www.linuxquestions.org/questions/linux-general-1/is-there-a-bash-command-for-picking-a-random-file-678687/

#!/bin/bash

# Reads a given directory and picks a random file.

# The directory you want to use. You could use "$1" instead if you
# wanted to parametrize it.
DIR="/path/to/"
# DIR="$1"

# Internal Field Separator set to newline, so file names with
# spaces do not break our script.
IFS='
'

if [[ -d "${DIR}" ]]
then
  # Runs ls on the given dir, and dumps the output into a matrix,
  # it uses the new lines character as a field delimiter, as explained above.
  #  file_matrix=($(ls -LR "${DIR}"))

  file_matrix=($(ls -R $DIR | awk '; /:$/&&f{s=$0;f=0}; /:$/&&!f{sub(/:$/,"");s=$0;f=1;next}; NF&&f{ print s"/"$0 }'))
  num_files=${#file_matrix[*]}

  # This is the command you want to run on a random file.
  # Change "ls -l" by anything you want, it's just an example.
  ls -l "${file_matrix[$((RANDOM%num_files))]}"
fi

exit 0

1

ম্যাকোস-এর মধ্যে বাছাই -R এবং shuf কমান্ড নেই, সুতরাং আমার একটি বাশ কেবলমাত্র সমাধান দরকার যা ডুপ্লিকেট ছাড়াই সমস্ত ফাইলকে এলোমেলো করে তোলে এবং এটি এখানে খুঁজে পায় না। এই সমাধানটি gniourf_gniourf এর সমাধান # 4 এর মতো, তবে আশা করি আরও ভাল মন্তব্য যুক্ত করুন।

স্ক্রিপ্টটি যদি এন এর সাথে একটি কাউন্টার ব্যবহার করে এন নমুনাগুলির পরে থামার জন্য পরিবর্তন করা সহজ হয় বা জি।

#!/bin/bash

array=(*)  # this is the array of files to shuffle
# echo ${array[@]}
for dummy in "${array[@]}"; do  # do loop length(array) times; once for each file
    length=${#array[@]}
    randomi=$(( $RANDOM % $length ))  # select a random index

    filename=${array[$randomi]}
    echo "Processing: '$filename'"  # do something with the file

    unset -v "array[$randomi]"  # set the element at index $randomi to NULL
    array=("${array[@]}")  # remove NULL elements introduced by unset; copy array
done

0

আমি এটি ব্যবহার করি: এটি অস্থায়ী ফাইল ব্যবহার করে তবে একটি ডিরেক্টরিতে গভীরভাবে যায় যতক্ষণ না এটি একটি নিয়মিত ফাইল খুঁজে পায় এবং এটি ফিরে না আসে।

# find for a quasi-random file in a directory tree:

# directory to start search from:
ROOT="/";  

tmp=/tmp/mytempfile    
TARGET="$ROOT"
FILE=""; 
n=
r=
while [ -e "$TARGET" ]; do 
    TARGET="$(readlink -f "${TARGET}/$FILE")" ; 
    if [ -d "$TARGET" ]; then
      ls -1 "$TARGET" 2> /dev/null > $tmp || break;
      n=$(cat $tmp | wc -l); 
      if [ $n != 0 ]; then
        FILE=$(shuf -n 1 $tmp)
# or if you dont have/want to use shuf:
#       r=$(($RANDOM % $n)) ; 
#       FILE=$(tail -n +$(( $r + 1 ))  $tmp | head -n 1); 
      fi ; 
    else
      if [ -f "$TARGET"  ] ; then
        rm -f $tmp
        echo $TARGET
        break;
      else 
        # is not a regular file, restart:
        TARGET="$ROOT"
        FILE=""
      fi
    fi
done;

-1

মিঃ কাংয়ের কাছ থেকে সামান্য ডক্টার্ড করা পার্ল সমাধান সম্পর্কে কীভাবে: ইউনিক্স কমান্ড লাইনে বা শেল স্ক্রিপ্টে আমি কোনও টেক্সট ফাইলের লাইনগুলি কীভাবে বদলাতে
পারি?

s ls | perl -MList :: Util = shuffle -e '@lines = shuffle (<>); @ লাইনগুলি প্রিন্ট করুন [0..4] '

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.