বাশ ব্যবহার করে তারিখগুলি কীভাবে লুপ করবেন?


87

আমার এ জাতীয় বাশ স্ক্রিপ্ট রয়েছে:

array=( '2015-01-01', '2015-01-02' )

for i in "${array[@]}"
do
    python /home/user/executeJobs.py {i} &> /home/user/${i}.log
done

এখন আমি বিভিন্ন তারিখের মধ্যে লুপ করতে চাই, উদাহরণস্বরূপ 2015-01-01 2015-01-31 পর্যন্ত।

বাশে অর্জন কীভাবে?

আপডেট :

সুন্দর করতে হবে: আগের রান শেষ হওয়ার আগে কোনও কাজ শুরু করা উচিত নয়। এই ক্ষেত্রে, যখন এক্সিকিউটজবস.পি.পি সম্পূর্ণ হয় তখন বাশ প্রম্পট $ফিরে আসবে।

যেমন আমি wait%1আমার লুপে অন্তর্ভুক্ত করতে পারি ?


আপনি কি জিএনইউ তারিখের প্ল্যাটফর্মে আছেন?
চার্লস ডাফি

4
এই লিঙ্কটি চেক করুন: গ্ল্যাটার- gotz.com/blog/2011/02/19/…
কিকিব্রো

4
বিটিডাব্লু, যেহেতু আপনার কাছে পাইথন ইন্টারপ্রেটার ব্যবহারযোগ্য তাই এটি datetimeপাইথন মডিউলটি ব্যবহার করে নির্ভরযোগ্য এবং বহনযোগ্য উপায়ে করা অনেক সহজ ।
চার্লস ডাফি

4
2015-01-01 2015-01-31 অবধি এক মাসেরও বেশি সময়কাল তারিখগুলি বিভক্ত হয় না, সুতরাং এটি খুব সাধারণ ঘটনা।
উইন্টারমুটে

4
... সুতরাং, যদি আপনি এমন একটি দেখছি প্রয়োজন থেকে wait(যেমন যখন আপনি না সমবর্তী প্রসেস কারণে ঘটছে বাগ), তারপর আপনি আরো আকর্ষণীয় কিছু আছে / আরো জটিল যা (ক আরো জটিল সমাধান প্রয়োজন, চলছে যেমন সাব-প্রসেসকে লকফাইলে উত্তরাধিকারী হিসাবে জিজ্ঞাসা করা), যা যথেষ্ট জটিলতা এবং তারিখের গাণিতিকের সাথে যথেষ্ট সম্পর্কযুক্ত নয় যে এটি একটি পৃথক প্রশ্ন হওয়া উচিত।
চার্লস ডাফি

উত্তর:


202

জিএনইউ তারিখ ব্যবহার:

d=2015-01-01
while [ "$d" != 2015-02-20 ]; do 
  echo $d
  d=$(date -I -d "$d + 1 day")

  # mac option for d decl (the +1d is equivalent to + 1 day)
  # d=$(date -j -v +1d -f "%Y-%m-%d" "2020-12-12" +%Y-%m-%d)
done

মনে রাখবেন যে এটি স্ট্রিং তুলনা ব্যবহার করে, এজটির প্রান্তের তারিখগুলির সম্পূর্ণ আইএসও 8601 স্বরলিপি প্রয়োজন (নেতৃস্থানীয় শূন্যগুলি অপসারণ করবেন না)। বৈধ ইনপুট ডেটা পরীক্ষা করার জন্য এবং যদি সম্ভব হয় তবে এটি বৈধ আকারে জোর করে, আপনি dateপাশাপাশি ব্যবহার করতে পারেন :

# slightly malformed input data
input_start=2015-1-1
input_end=2015-2-23

# After this, startdate and enddate will be valid ISO 8601 dates,
# or the script will have aborted when it encountered unparseable data
# such as input_end=abcd
startdate=$(date -I -d "$input_start") || exit -1
enddate=$(date -I -d "$input_end")     || exit -1

d="$startdate"
while [ "$d" != "$enddate" ]; do 
  echo $d
  d=$(date -I -d "$d + 1 day")
done

একটি চূড়ান্ত সংযোজন : $startdateএটি আগে যাচাই করা $enddate, আপনি যদি কেবল 1000 এবং 9999 বছরের মধ্যে তারিখগুলি আশা করেন তবে আপনি কেবল স্ট্রিং তুলনাটি ব্যবহার করতে পারেন:

while [[ "$d" < "$enddate" ]]; do

10000 বছর পেরিয়ে খুব নিরাপদ দিকে থাকতে, যখন অভিধানিক তুলনা ভেঙে যায়, ব্যবহার করুন

while [ "$(date -d "$d" +%Y%m%d)" -lt "$(date -d "$enddate" +%Y%m%d)" ]; do

অভিব্যক্তিটি একটি সংখ্যাসূচক আকারে $(date -d "$d" +%Y%m%d)রূপান্তরিত $dহয়, অর্থাত্ 2015-02-23পরিণত হয় 20150223এবং ধারণাটি এই ফর্মের তারিখগুলিকে সংখ্যার সাথে তুলনা করা যায়।


4
অবশ্যই, কেন না। এটি কেবল একটি শেল লুপ, এটি তারিখগুলি ব্যবহার করে কারণ পুনরাবৃত্তিকারী এটির ভিতরে আপনি কী করতে পারেন তা পরিবর্তন করে না।
উইন্টারমুটে

4
@ সিরবেনবেঞ্জি ... ... বলেছিল যে %1একটি কাজ নিয়ন্ত্রণ নির্মাণ, এবং আপনি যদি স্পষ্টভাবে নিজের উপর এটি না চালু করেন তবে জব নিয়ন্ত্রণটি অবিচ্ছিন্ন স্ক্রিপ্টগুলিতে বন্ধ করা হবে। কোনও স্ক্রিপ্টের অভ্যন্তরে পৃথক উপ-প্রসেসগুলি উল্লেখ করার সঠিক উপায় হ'ল পিআইডি এবং তারপরেও প্রক্রিয়াগুলি সমাপ্ত হওয়ার জন্য অপেক্ষা করা স্বয়ংক্রিয় হয় যদি না সেগুলি আপনার কোড দ্বারা স্পষ্টভাবে ব্যাকগ্রাউন্ড হয় (এ হিসাবে &), বা তারা স্ব-বিচ্ছিন্ন হয় (যে ক্ষেত্রে waitএমনকি কাজ করবে না, এবং শেলকে দেওয়া পিআইডি স্ব-পটভূমিতে ব্যবহৃত ডাবল-কাঁটাচামচ প্রক্রিয়া দ্বারা বাতিল হয়ে যাবে)।
চার্লস ডাফি

4
ঘনিষ্ঠভাবে দেখার পরে, এটি প্রদর্শিত হবে যে লিপ সেকেন্ডগুলি ইউএনআইএক্স টাইমস্ট্যাম্প থেকে বাদ দেওয়া হয়েছে, যাতে কিছু টাইমস্ট্যাম্পগুলি দুই সেকেন্ডের ব্যবস্থাকে বোঝায়। এটি আপাতদৃষ্টিতে উপ-দ্বিতীয় পরিসরে বাস্তবায়ন করতে ´gettimeofday` কে অত্যন্ত আকর্ষণীয় করে তোলে এবং আমি মনে করি আমাদের নিজেদের ভাগ্যবান গণ্য করা উচিত যে লিপ সেকেন্ড কখনও এক বছর থেকে সরানো হয়নি । এর অর্থ আমাকে নিজের সংশোধন করতে হবে: একটি ইউনিক্স টাইমস্ট্যাম্পে 86400 সেকেন্ড যুক্ত করা যুক্তিযুক্তভাবে সবসময় একটি দিন যুক্ত করার মতোই হয়, যেহেতু নির্দিষ্টভাবে 2016-12-31T23: 59: 60 উল্লেখ করার কোনও উপায় নেই। তিল
উইন্টারমিট

4
আপনার প্রথম কোডটি চালানো (sh পরীক্ষা.sh) আমাকে ত্রুটি দেয়: তারিখ: অবৈধ বিকল্প - আমি ব্যবহার: তারিখ [-jnRu] [-ddst] [-r সেকেন্ড] [-t পশ্চিম] [-ভি [+ | | -] ভাল [ymwdHMS]] ... [- fmt তারিখ | [[[মিমি] ডিডি] এইচএইচ] এমএম [[সিসি] ইয়ি] [। এসএস]] [+ ফর্ম্যাট]
ডোরিয়েন

4
MacOS এর জন্য এটি কাজ করে না, প্রথম GNU তারিখ ইনস্টল করবে apple.stackexchange.com/questions/231224/...
জেইমি Agudo

22

ব্রেস সম্প্রসারণ :

for i in 2015-01-{01..31} …

আরও:

for i in 2015-02-{01..28} 2015-{04,06,09,11}-{01..30} 2015-{01,03,05,07,08,10,12}-{01..31} …

প্রুফ:

$ echo 2015-02-{01..28} 2015-{04,06,09,11}-{01..30} 2015-{01,03,05,07,08,10,12}-{01..31} | wc -w
 365

কমপ্যাক্ট / নেস্টেড:

$ echo 2015-{02-{01..28},{04,06,09,11}-{01..30},{01,03,05,07,08,10,12}-{01..31}} | wc -w
 365

আদেশ দেওয়া হয়েছে, যদি তা গুরুত্বপূর্ণ:

$ x=( $(printf '%s\n' 2015-{02-{01..28},{04,06,09,11}-{01..30},{01,03,05,07,08,10,12}-{01..31}} | sort) )
$ echo "${#x[@]}"
365

যেহেতু এটি অর্ডারমুক্ত নয়, আপনি কেবল এখান থেকে ঝাঁপিয়ে পড়তে পারেন:

$ echo {2015..2030}-{02-{01..28},{04,06,09,11}-{01..30},{01,03,05,07,08,10,12}-{01..31}} {2016..2028..4}-02-29 | wc -w
5844

4
লিপ বছর সম্পর্কে কি?
উইন্টারমুটে

আমি কি তাহলে ব্যবহার করতে পারি python /home/user/executeJobs.py 2015-01-{01..31} &> /home/user/2015-01-{01..31}.log ?
স্টিভ কে

@ সিরবেনবেঞ্জি এটি নির্ভর করে executeJobs.py
কোজিরো

আমি অবশ্যই বলতে পারি এক্সিকিউট জবসের জন্য তারিখের প্যারামিটার প্রয়োজন এবং সম্পূর্ণ করার জন্য আমাকে প্রতিটি রানের জন্য অপেক্ষা করতে হবে। এটি একটি বিগ ডেটা কাজ এবং পূর্ববর্তী প্রতিটি রান শেষ হওয়ার আগে কোনও পরিস্থিতিতে শুরু করা উচিত নয়। আমার আগে এই সম্পর্কে চিন্তা করা উচিত ছিল, এটি ভুলে যাওয়ার জন্য দুঃখিত।
স্টিভ কে

11
start='2019-01-01'
end='2019-02-01'

start=$(date -d $start +%Y%m%d)
end=$(date -d $end +%Y%m%d)

while [[ $start -le $end ]]
do
        echo $start
        start=$(date -d"$start + 1 day" +"%Y%m%d")

done

3

আমার একই সমস্যা ছিল এবং আমি উপরের উত্তরগুলির কয়েকটি চেষ্টা করেছি, সম্ভবত সেগুলি ঠিক আছে, তবে ম্যাকস ব্যবহার করে আমি যা করার চেষ্টা করছিলাম সে বিষয়ে উত্তরগুলির কোনওটিরই ঠিক করা হয়নি।

আমি অতীতে তারিখগুলি পুনরাবৃত্তি করার চেষ্টা করছিলাম, এবং নিম্নলিখিতটি আমার পক্ষে কাজ করেছে:

#!/bin/bash

# Get the machine date
newDate=$(date '+%m-%d-%y')

# Set a counter variable
counter=1 

# Increase the counter to get back in time
while [ "$newDate" != 06-01-18 ]; do
  echo $newDate
  newDate=$(date -v -${counter}d '+%m-%d-%y')
  counter=$((counter + 1))
done

আশা করি এটা সাহায্য করবে.


আমি কোনও পরিবর্তনশীল নামটি ব্যবহার না করার প্রস্তাব দিচ্ছি যা খুব শক্তিশালী বিট-ফর-বিট কপি কমান্ডের সাথে মিলে যায় তবে তা কেবল আমারই।
মেরিলফরাজ 0 '20

সহজ উপায় হ'ল ম্যাকোসের gdateপরিবর্তে ব্যবহার করা date
উত্তরত্রী

2

যদি কেউ ইনপুট তারিখ থেকে নীচের যে কোনও ব্যাপ্তিতে লুপ করতে চায় তবে এটি yyyyMMdd আকারে আউটপুট মুদ্রণ করবে ...

#!/bin/bash
in=2018-01-15
while [ "$in" != 2018-01-25 ]; do
  in=$(date -I -d "$in + 1 day")
  x=$(date -d "$in" +%Y%m%d)
  echo $x
done

2

আমার এআইএক্স, বিএসডি, লিনাক্স, ওএস এক্স এবং সোলারিসের তারিখগুলি লুপ করা দরকার। dateকমান্ড ব্যবহারের অন্তত পোর্টেবল এবং সবচেয়ে দু: স্থ কমান্ড প্ল্যাটফর্ম জুড়ে আমি সম্মুখীন অন্যতম। আমি এটি লিখতে আরও সহজ পেয়েছিmy_date কমান্ড যা কেবল সর্বত্রই কাজ করেছে।

নীচের সি প্রোগ্রামটি একটি শুরুর তারিখ নেয় এবং এটি থেকে দিন যোগ করে বা বিয়োগ করে। যদি কোনও তারিখ সরবরাহ না করা হয় তবে এটি বর্তমান তারিখ থেকে দিনগুলি যোগ করে বা বিয়োগ করে।

my_dateকমান্ড আপনাকে নিম্নলিখিত সর্বত্র সম্পাদন করতে অনুমতি দেয়:

start="2015-01-01"
stop="2015-01-31"

echo "Iterating dates from ${start} to ${stop}."

while [[ "${start}" != "${stop}" ]]
do
    python /home/user/executeJobs.py {i} &> "/home/user/${start}.log"
    start=$(my_date -s "${start}" -n +1)
done

এবং সি কোড:


2

পাইপগুলি (|) উত্তোলনের মাধ্যমে বাশ সবচেয়ে ভাল লেখা। এর ফলে স্মৃতিশক্তি দক্ষ এবং সমবর্তী (দ্রুত) প্রক্রিয়াজাতকরণ হওয়া উচিত। আমি নিম্নলিখিত লিখতে হবে:

seq 0 100 | xargs printf "20 Aug 2020 - %sdays\n" \
  | xargs -d '\n' -l date -d

নিম্নলিখিতটি তার তারিখটি প্রিন্ট করবে 20 aug 2020এবং এর 100 দিন আগে তারিখগুলি মুদ্রণ করবে।

এই অনলাইনারটি একটি ইউটিলিটি তৈরি করা যেতে পারে।

#!/usr/bin/env bash

# date-range template <template>

template="${1:--%sdays}"

export LANG;

xargs printf "$template\n" | xargs -d '\n' -l date -d

ডিফল্টরূপে আমরা একসাথে গত 1 দিনটিতে পুনরাবৃত্তি করতে পছন্দ করি।

$ seq 10 | date-range
Mon Mar  2 17:42:43 CET 2020
Sun Mar  1 17:42:43 CET 2020
Sat Feb 29 17:42:43 CET 2020
Fri Feb 28 17:42:43 CET 2020
Thu Feb 27 17:42:43 CET 2020
Wed Feb 26 17:42:43 CET 2020
Tue Feb 25 17:42:43 CET 2020
Mon Feb 24 17:42:43 CET 2020
Sun Feb 23 17:42:43 CET 2020
Sat Feb 22 17:42:43 CET 2020

ধরা যাক আমরা একটি নির্দিষ্ট তারিখ পর্যন্ত তারিখ উত্পন্ন করতে চাই। সেখানে পৌঁছতে আমাদের কতগুলি পুনরাবৃত্তি দরকার তা আমরা এখনও জানি না। ধরা যাক টম জন্মগ্রহণ করেছেন 1 জানুয়ারী 2001. আমরা নির্দিষ্ট তারিখের মধ্যে প্রতিটি তারিখ উত্পন্ন করতে চাই। আমরা সেড ব্যবহার করে এটি অর্জন করতে পারি।

seq 0 $((2**63-1)) | date-range | sed '/.. Jan 2001 /q'

$((2**63-1))কৌতুক একটি বড় পূর্ণসংখ্যা তৈরি করতে ব্যবহার করা হয়।

একবার সেড প্রস্থান করলে তা তারিখ-ব্যাপ্তি ইউটিলিটিটি থেকেও বেরিয়ে আসবে।

3 মাসের ব্যবধান ব্যবহার করেও কেউ পুনরাবৃত্তি করতে পারে:

$ seq 0 3 12 | date-range '+%smonths'
Tue Mar  3 18:17:17 CET 2020
Wed Jun  3 19:17:17 CEST 2020
Thu Sep  3 19:17:17 CEST 2020
Thu Dec  3 18:17:17 CET 2020
Wed Mar  3 18:17:17 CET 2021

আমি একটি ডেট-সেক রেপোজিটরি তৈরি করেছি যা এই ধারণার উন্নতি করে এবং এটি আরও ভাল করে দলিল করে। github.com/bas080/date-seq
bas080

1

আপনি যদি ব্যস্তবক্সের তারিখের সাথে আটকে থাকেন তবে আমি টাইমস্ট্যাম্পগুলির সাথে কাজ করা সবচেয়ে নির্ভরযোগ্য পদ্ধতির হিসাবে খুঁজে পেয়েছি:

STARTDATE="2019-12-30"
ENDDATE="2020-01-04"

start=$(date -d $STARTDATE +%s)
end=$(date -d $ENDDATE +%s)

d="$start"
while [[ $d -le $end ]]
do
    date -d @$d +%Y-%m-%d

    d=$(( $d + 86400 ))
done

এটি আউটপুট দেবে:

2019-12-30
2019-12-31
2020-01-01
2020-01-02
2020-01-03
2020-01-04

ইউনিক্স টাইমস্ট্যাম্পে লিপ সেকেন্ড অন্তর্ভুক্ত থাকে না, সুতরাং 1 দিন সর্বদা হ'ল 86400 সেকেন্ডের সমান।

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