कमांड 'डेट -d @xxxxxx' और 'find//' को कैसे चेन करें?


14

मेरे पास निर्देशिकाएं हैं जिनके नाम टाइमस्टैम्प हैं, 1970-01-01 से मिलीसेकंड में दिए गए हैं:

1439715011728
1439793321429
1439879712214
.
.

और मुझे एक आउटपुट चाहिए जैसे:

1442039711    Sat Sep 12 08:35:11 CEST 2015
1442134211    Sun Sep 13 10:50:11 CEST 2015
1442212521    Mon Sep 14 08:35:21 CEST 2015
.
.

मैं सभी निर्देशिकाओं को कमांड द्वारा सूचीबद्ध कर सकता हूं:

find ./ -type d | cut -c 3-12

लेकिन मैं आउटपुट को अगले कमांड पर नहीं रख सकता: date -d @xxxxxxऔर आउटपुट में हेरफेर करता हूं ।

मैं यह कैसे कर सकता हूँ?


2
उन टाइमस्टैम्प्स का युगांतर कैसे होता है? क्योंकि आपकी संख्या बहुत लंबी है ... (वह पहला एक है Fri Oct 2 05:35:28 47592)
सोब्रीक

1
@ शोब्रिक स्पष्ट रूप से युग के बाद से मिलीसेकंड।
गिलेस एसओ- बुराई को रोकना '

जवाबों:


10

आप सही रास्ते पर हैं (एक सरल समाधान के लिए, केवल 2 या 3 कमांड चला रहे हैं, नीचे देखें)। आपको वर्तमान निर्देशिका से छुटकारा पाने के *बजाय उपयोग करना चाहिए ./और यह कुछ हद तक मिलीसेकंड के काटने को सरल करता है, फिर परिणाम को GNU parallelया to में पाइप करें xargs:

find * -type d | cut -c 1-10 | parallel date --date=@{} +%c

लेना

Sat 12 Sep 2015 08:35:11 CEST
Sun 13 Sep 2015 10:50:11 CEST
Mon 14 Sep 2015 08:35:21 CEST

और इससे पहले कि आपके उदाहरण इंगित करता है सेकंड ऑफसेट जोड़ने के लिए:

find * -type d | cut -c 1-10 | parallel 'echo "{} "  $(date --date=@{} +%c)'

या:

find * -type d | cut -c 1-10 | xargs -I{} bash -c 'echo "{} "  $(date --date=@{} +%c)'

लेना:

1442039711  Sat 12 Sep 2015 08:35:11 CEST
1442134211  Sun 13 Sep 2015 10:50:11 CEST
1442212521  Mon 14 Sep 2015 08:35:21 CEST

हालांकि यह आसान है:

find * -type d -printf "@%.10f\n" | date -f - +'%s  %c'

जो आपको एक बार फिर से अनुरोधित आउटपुट देता है।

उपयोग करने *का नुकसान यह है कि आप इसके विस्तार के लिए अपनी कमांडलाइन द्वारा सीमित हैं, हालांकि लाभ यह है कि आप अपनी निर्देशिकाओं को टाइमस्टैम्प मूल्य द्वारा क्रमबद्ध करते हैं। यदि निर्देशिकाओं की संख्या एक समस्या का उपयोग है -mindepth 1, लेकिन आदेश खोना:

find ./ -mindepth 1 -type d -printf "@%.10f\n" | date -f - +'%s  %c'

और sortयदि आवश्यक हो तो डालें :

find ./ -mindepth 1 -type d -printf "@%.10f\n" | sort | date -f - +'%s  %c'

¹ यह मानता है कि कोई नेस्टेड उपनिर्देशिका नहीं हैं, जैसा कि आपके उदाहरण से लगता है। तुम भी उपयोग कर सकते हैं ./ -mindepth 1के बजाय*
² आप बदल सकते हैं parallelके साथ xargs -I{}यह सिर्फ अधिक वर्बोज़ @hobbs के रूप में यहाँ और @don_crissti का सुझाव दिया,। ³ गाइल्स के जवाब के आधार पर dates फ़ाइल पढ़ने की क्षमताओं का उपयोग करें


या xargsअगर आपके पास नहीं है parallel, जो बहुत से लोग शायद नहीं करते हैं।
हॉब्स

@hobbs AFAIK के xargsपास यह निर्दिष्ट करने का विकल्प नहीं है कि तर्क कहां जाता parallelहै {}
एंथन

4
यह करता है:find ./ -type d | cut -c 3-12 | xargs -I{} date --d @{} +'%Y-%m-%d'
don_crissti

@ यदि आप -Iविकल्प का उपयोग करते हैं तो यह करता है।
हॉब्स

1
@Anthon, GNU लंबे विकल्पों को तब तक संक्षिप्त किया जा सकता है जब तक वे अस्पष्ट न हों। --dया --daजीएनयू के वर्तमान संस्करण के साथ काम करेंगे date, लेकिन यह दिन काम करना बंद कर सकता है dateप्रस्तुत किया एक --dalekविकल्प (Dalek कैलेंडर में दिनांक के लिए)।
स्टीफन चेज़लस

10

मैं लूप में प्रति फ़ाइल कई कमांड चलाने से बचता हूँ। चूंकि आप पहले से ही GNUism का उपयोग कर रहे हैं:

find . ! -name . -prune -type d |
  awk '{t = substr($0, 3, 10); print t, strftime("%a %b %d %T %Z %Y", t)}'

जो सिर्फ दो कमांड चलाता है। strftime()ग्नू-विशिष्ट है, जैसे date -d


यह निर्देशिका नामों के मिलीसेकंड में कटौती नहीं करता है, लेकिन अनुरोधित पहले 10 के बजाय पूर्ण 13 पात्रों को प्रदर्शित करता है
एंथॉन

@ एंथन, आह हाँ, वह आवश्यकता याद आती है। अब ठीक होना चाहिए।
स्टीफन चेज़लस

8

तुम्हारे पास पहले से है:

find ./ -type d | cut -c 3-12

जो संभवतः आपको युग प्रारूप में टाइमस्टैम्प हो जाता है। अब एक समय लूप जोड़ें:

find ./ -type d | cut -c 3-12 | while read datestamp
do
    printf %s "$datestamp"
    date -d "@$datestamp"
done

ध्यान दें कि कुछ गोले में, उस सिंटैक्स को उप-भाग में लूप मिलता है, जिसका अर्थ है कि यदि आप एक चर सेट करने का प्रयास करते हैं, तो लूप छोड़ने के बाद यह दिखाई नहीं देगा। इसे ठीक करने के लिए, आपको चीजों को उनके सिर पर थोड़ा मोड़ना होगा:

while read datestamp
do
    printf %s "$datestamp"
    date -d "@$datestamp"
done < <(find ./ -type d | cut -c 3-12)

जो findउप-प्रकार में रखता है, और मुख्य लूप में लूप रखता है। यदि आप लूप के अंदर से एक परिणाम का पुन: उपयोग करने के लिए देख रहे हैं, तो सिंटैक्स (एटी एंड टी ksh, zshऔर bashविशिष्ट) की आवश्यकता है।


परवाह किए बिना, यह कहते हुए कि यह bash-specific सही नहीं है :)
Wouter Verhelst

वास्तव में, जैसा कि आपने शुरू में लिखा था, done <(find)इसके बजाय done < <(find), यह सही था yash(जहां <(...)प्रक्रिया पुनर्निर्देशन है, प्रक्रिया प्रतिस्थापन नहीं), इसलिए मेरा संपादन थोड़ा घुड़सवार था क्योंकि यह आपके लिए इसका मतलब हो सकता था।
स्टीफन चेजलस

6

यदि आपके पास जीएनयू तिथि है, तो यह इनपुट फ़ाइल से पढ़ी गई तिथियों को परिवर्तित कर सकती है। आपको बस टाइमस्टैम्प की थोड़ी मालिश करने की आवश्यकता है ताकि यह उन्हें पहचान सके। यूनिक्स युग पर आधारित टाइमस्टैम्प के लिए इनपुट सिंटैक्स @सेकंड की संख्या के बाद होता है, जिसमें दशमलव बिंदु हो सकता है।

find ./ -type d ! -name '*[!0-9]*' |
sed -e 's~.*/~@~' -e 's~[0-9][0-9][0-9]$~.&~' |
date -f - +'%s  %c'

dateफ़ाइल फ़ाइल पढ़ने के उपयोग के लिए +1 । यह date: invalid date ‘@’वर्तमान निर्देशिका ( ./) के अनुवाद के कारण देगा । और चूंकि आप मिलीसेकंड को दूर फेंक सकते हैं, आप sedअंतिम 3 वर्णों को छोड़ने के लिए दूसरे संपादन को सरल बना सकते हैं । या उस सब को हटा दें और उपयोग करेंfind * -type d -printf "@%.10f" | date ...
एंथन

5

मैं इसे पूरी तरह से करना चाहता हूं - टाइमस्टैम्प की सूची में फ़ीड:

#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;

while ( my $ts = <DATA> ) { 
   chomp ( $ts );
   my $t = Time::Piece->new();
   print $t->epoch, " ", $t,"\n";
}

__DATA__
1442039711  
1442134211  
1442212521

यह आउटपुट:

1442039711 Sat Sep 12 07:35:11 2015
1442134211 Sun Sep 13 09:50:11 2015
1442212521 Mon Sep 14 07:35:21 2015

यदि आप एक विशिष्ट आउटपुट प्रारूप चाहते हैं, तो आप strftimeउदाहरण के लिए उपयोग कर सकते हैं :

print $t->epoch, " ", $t->strftime("%Y-%m-%d %H:%M:%S"),"\n";

जो इसे आपके पाइप में एक लाइनर में बदल देगा:

 perl -MTime::Piece -nle '$t=Time::Piece->new($_); print $t->epoch, "  ", $t, "\n";'

लेकिन मैं शायद इसके बजाय File::Findमॉड्यूल का उपयोग करने और बदले में पूरी बात करने का सुझाव दूंगा। यदि आप इसे काटने से पहले अपनी निर्देशिका संरचना का उदाहरण देते हैं, तो मैं आपको एक उदाहरण दूंगा। लेकिन यह कुछ इस तरह होगा:

#!/usr/bin/env perl

use strict;
use warnings;
use Time::Piece;
use File::Find; 

sub print_timestamp_if_dir {
   #skip if 'current' item is not a directory. 
   next unless -d; 
   #extract timestamp (replicating your cut command - I think?)
   my ( $timestamp ) = m/.{3}(\d{9})/; #like cut -c 3-12;

   #parse date
   my $t = Time::Piece->new($timestamp);
   #print file full path, epoch time and formatted time; 
   print $File::Find::name, " ", $t->epoch, " ", $t->strftime("%Y-%m-%d %H:%M:%S"),"\n";
}

find ( \&print_timestamp_if_dir, "." ); 

2

के साथ zshऔर strftime बिलिन:

zmodload zsh/datetime
for d (*(/))
strftime '%s %a %b %d %T %Z %Y' $d

यह मानता है कि वर्तमान निर्देशिका में आपके सभी निर्देशिका नाम वास्तव में युग के हैं।
आगे फ़िल्टरिंग / प्रसंस्करण संभव है, बशर्ते कि आपके उदाहरण में उन नंबरों को कैसे संसाधित किया जाए (वे राजकुमारी लीया और ल्यूक स्काईवॉकर की जन्मतिथि की तुलना में अधिक बार की तरह दिखते हैं ...) जैसे कि कम से कम मेल खाने वाले निर्देशिका नामों के लिए पुनरावर्ती खोजें 10 अंक और पहले 10 अंकों के आधार पर तारीख की गणना करें:

setopt extendedglob
zmodload zsh/datetime
for d (**/[0-9](#c10,)(/))
strftime '%s %a %b %d %T %Z %Y' ${${d:t}:0:10}

2

GNU समानांतर का उपयोग:

find ./ -type d | cut -c 3-12 | parallel -k 'echo {} `date -d @{}`'

यदि आप स्थान के बजाय \ t स्वीकार कर सकते हैं:

find ./ -type d | cut -c 3-12 | parallel -k --tag date -d @{}

ध्यान दें कि parallelमें लिखा है perl। ऐसा लगता है कि perlएक strftime()ऑपरेटर है overkill लगता है । जैसेperl -MPOSIX -lpe '$_.=strftime(" %c", localtime substr $_, 2, 10)'
स्टीफन चेज़लस

2
1. यह छोटा है। 2. आपको पर्ल सीखने की जरूरत नहीं है।
ओले तांगे

1
यह 27% कम है, लेकिन यह परिमाण के कम कुशल होने के कई आदेश हैं (मेरे द्वारा किए गए परीक्षण में लगभग 800 गुना धीमा; इस पर विचार करें कि यह एक शेल (आपका शेल, नॉट / बिन / श) और प्रत्येक पंक्ति के लिए एक डेट कमांड की आवश्यकता है) और सिस्टम के लिए अमित्र है क्योंकि यह एक ही बार में सभी सीपीयू पर बोझ डालता है। और आपको अभी भी सीखने की जरूरत है parallel। IMO, parallelCPU गहन कार्यों को समानांतर करने के लिए एक महान उपकरण है, लेकिन यहाँ इस तरह के कार्य के लिए वास्तव में उपयुक्त नहीं है।
स्टीफन चेजलस

वहाँ बहुत सारे संदर्भ हैं जहां दक्षता चिंता का विषय नहीं है, इसलिए यह अभी भी एक स्वीकार्य समाधान है, लेकिन यह अभी भी प्रदर्शन के मुद्दे पर ध्यान देने योग्य है, खासकर जब यह विचार करते हुए कि समानांतर आमतौर पर लोगों के दिमाग में उच्च प्रदर्शन के साथ गाया जाता है।
स्टीफन चेजलस

0

आम तौर पर पाते हैं कि कमांड का उपयोग execतर्क के साथ किसी भी कमांड के साथ किया जा सकता है।

आपके मामले में, आप इस तरह कर सकते हैं:

find . -type d | cut -c 3-12 | while read line
do
       echo -n "${line}  "
       date -d $line
done

0

पायथन का उपयोग करना (यह संभवतः सबसे धीमा समाधान है)

for i in $(ls -A); do echo $i | xargs python -c "from sys import argv;from time import strftime;from datetime import datetime;print datetime.fromtimestamp(float(argv[1][:-3])).strftime('%Y-%m-%d %H:%M:%S'),'---',argv[1]"; done

देता है:

2015-08-30 08:48:59 --- 1440917339340
2015-08-31 08:00:22 --- 1441000822458
2015-09-01 08:00:32 --- 1441087232437
2015-09-01 16:48:43 --- 1441118923773
2015-09-02 08:00:11 --- 1441173611869
2015-09-03 08:00:32 --- 1441260032393
2015-09-04 08:00:21 --- 1441346421651

अजगर में यह सब क्यों नहीं? पाइपों के एक समूह का पीछा करने के बजाय?
सोब्रीक

यह बेहतर समझ में आता है। मैं सहमत हूँ।
लुकज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.