बैश में एक पाठ फ़ाइल से एक सरणी बनाना


86

एक स्क्रिप्ट एक यूआरएल लेता है, आवश्यक फ़ील्ड के लिए यह पार्स करता है, और पुनर्निर्देश इसके उत्पादन एक फ़ाइल में सहेजने के लिए, file.txt । किसी फ़ील्ड के मिलने पर आउटपुट को हर बार एक नई लाइन पर सहेजा जाता है।

file.txt

A Cat
A Dog
A Mouse 
etc... 

मैं file.txtएक नई स्क्रिप्ट में इससे एक ऐरे को लेना और बनाना चाहता हूं , जहां एरो में हर लाइन का अपना स्ट्रिंग वैरिएबल हो। अब तक मैंने कोशिश की है:

#!/bin/bash

filename=file.txt
declare -a myArray
myArray=(`cat "$filename"`)

for (( i = 0 ; i < 9 ; i++))
do
  echo "Element [$i]: ${myArray[$i]}"
done

जब मैं इस स्क्रिप्ट को चलाता हूं, तो व्हॉट्सएप के परिणाम शब्दों में विभाजित हो जाते हैं और मिलने के बजाय

वांछित उत्पादन

Element [0]: A Cat 
Element [1]: A Dog 
etc... 

मैं इसे प्राप्त कर रहा हूं:

वास्तविक उत्पादन

Element [0]: A 
Element [1]: Cat 
Element [2]: A
Element [3]: Dog 
etc... 

मैं नीचे दिए गए लूप को कैसे समायोजित कर सकता हूं कि प्रत्येक पंक्ति पर संपूर्ण स्ट्रिंग सरणी में प्रत्येक चर के साथ एक-से-एक अनुरूप होगा?


5
यह बश FAQ 001 क्या है। इसके अलावा बश FAQ 005 में सरणी विषय का यह खंड
इतन रिस्नर

1
मैं इसे stackoverflow.com/questions/11393817/… के डुप्लिकेट के रूप में लिंक करूँगा , लेकिन वहाँ स्वीकृत उत्तर भयानक है।
चार्ल्स डफी

Etan, इतनी जल्दी और सटीक उत्तर के लिए बहुत बहुत धन्यवाद! मैंने मंचों में अपने प्रश्न को खोजने की कोशिश की थी, लेकिन स्टैकओवरफ्लो पर अक्सर पूछे जाने वाले प्रश्न देखने के लिए नहीं सोचा था। Mapfile कमांड ने मेरी ज़रूरतों को पूरा किया! धन्यवाद फिर से :) खंड 2.1 में उत्तर ।
user2856414

2
(लिंक को विपरीत दिशा में सेट करें, क्योंकि हमारे पास वहां से बेहतर स्वीकृत उत्तर है)।
चार्ल्स डफी

जवाबों:


107

mapfileकमांड का उपयोग करें :

mapfile -t myArray < file.txt

त्रुटि का उपयोग कर रहा है for- किसी फ़ाइल की पंक्तियों पर लूप करने का मुहावरेदार तरीका है:

while IFS= read -r line; do echo ">>$line<<"; done < file.txt

देखें BashFAQ / 005 अधिक जानकारी के लिए।


5
चूंकि इसे कैनोनिकल q & a के रूप में प्रचारित किया जा रहा है, आप यह भी शामिल कर सकते हैं कि लिंक में क्या उल्लेख किया गया है while IFS= read -r; do lines+=("$REPLY"); done <file:।
फेडोरक्वी 'एसओ स्टॉप हर्टिंग'

10
4.fx से पहले
मैपफाइल

14
बैश 4 अब लगभग 5 साल का है। अपग्रेड करें।
ग्लेन जैकमैन

5
2009 में बैश 4 के रिलीज़ होने के बावजूद, @ ericslaw की टिप्पणी प्रासंगिक बनी हुई है क्योंकि कई मशीनें अभी भी बैश 3.x के साथ जहाज करती हैं (और अपग्रेड नहीं करेंगी, इसलिए जब तक बैश को GPLv3 के तहत जारी नहीं किया जाता)। यदि आप पोर्टेबिलिटी में रुचि रखते हैं, तो यह ध्यान रखना महत्वपूर्ण है
डी नोवो

12
मुद्दा यह नहीं है कि एक डेवलपर एक उन्नत संस्करण स्थापित नहीं कर सकता है, यह है कि एक डेवलपर को यह पता होना चाहिए कि एक स्क्रिप्ट का उपयोग mapfileअतिरिक्त चरणों के बिना कई मशीनों पर अपेक्षित रूप से नहीं चलेगा। @ericslaw macs भविष्य के लिए भविष्यवक्ता 3.2.57 के साथ जहाज चलाना जारी रखेंगे। अधिक हाल के संस्करण एक लाइसेंस का उपयोग करते हैं जिन्हें उन चीजों को साझा करने या अनुमति देने के लिए सेब की आवश्यकता होती है जो वे साझा या अनुमति नहीं देना चाहते हैं।
डे नोवो

23

mapfileऔर readarray(जो पर्यायवाची हैं) बैश संस्करण 4 और उसके बाद के संस्करण में उपलब्ध हैं। यदि आपके पास बैश का पुराना संस्करण है, तो आप फ़ाइल को किसी सरणी में पढ़ने के लिए एक लूप का उपयोग कर सकते हैं:

arr=()
while IFS= read -r line; do
  arr+=("$line")
done < file

यदि फ़ाइल में एक अधूरी (लापता नई पंक्ति) है, तो आप इस विकल्प का उपयोग कर सकते हैं:

arr=()
while IFS= read -r line || [[ "$line" ]]; do
  arr+=("$line")
done < file

सम्बंधित:


मुझे लगता है कि मुझे IFS= read -r line || [[ "$line" ]]इसे काम करने के लिए चारों ओर कोष्ठक लगाना होगा। अन्यथा, यह महान काम करता है!
तातियाना राचेवा

@ टाटियानाराचेवा: क्या यह नहीं है कि अर्धविराम जो पहले गायब था do?
कोडफोस्टर

9

आप भी यह कर सकते हैं:

oldIFS="$IFS"
IFS=$'\n' arr=($(<file))
IFS="$oldIFS"
echo "${arr[1]}" # It will print `A Dog`.

ध्यान दें:

फ़ाइल नाम का विस्तार अभी भी होता है। उदाहरण के लिए, अगर वहाँ एक शाब्दिक के साथ एक पंक्ति है, तो *यह वर्तमान फ़ोल्डर में सभी फ़ाइलों तक विस्तृत होगा। इसलिए इसका उपयोग केवल तभी करें जब आपकी फ़ाइल इस तरह के परिदृश्य से मुक्त हो।


क्या IFSकेवल अस्थायी रूप से सेट करने का कोई तरीका है (ताकि वह इस आदेश के बाद अपने मूल मूल्य को फिर से प्राप्त कर सके), जबकि अभी भी असाइनमेंट जारी है arr?
ह्यूजेस

1
ध्यान दें कि फ़ाइल नाम का विस्तार अभी भी होता है; जैसेIFS=$'\n' arr=($(echo 'a 1'; echo '*'; echo 'b 2')); printf "%s\n" "${arr[@]}"
ह्यूगस

@ ह्यूजेस: हां, फ़ाइल नाम का विस्तार अभी भी होता है। मैं जानकारी के उस बिट .. जोड़ देंगे ..
जाहिद

क्षमा करें, मैं असहमत हूं। वर्तमान शेल में IFS=... commandनहीं बदलता IFSहै। हालांकि, IFS=... other_variable=...(किसी भी आदेश के बिना) दोनों में बदल जाती है IFSऔर other_variableवर्तमान खोल में।
ह्यूजेस

1
धन्यवाद! यह काम; यह दुर्भाग्यपूर्ण है कि arr=नोटेशन ( mapfile/ की तुलना में readarray) जैसा कोई सरल तरीका नहीं है ।
ह्यूजेस

4

आप बस फ़ाइल से प्रत्येक पंक्ति पढ़ सकते हैं और इसे एक सरणी में असाइन कर सकते हैं।

#!/bin/bash
i=0
while read line 
do
        arr[$i]="$line"
        i=$((i+1))
done < file.txt

1
आप ऐरे तक कैसे पहुँच सकते हैं?
होला

4

मैपफाइल या रीड-ए का उपयोग करें

हमेशा शेलचेक का उपयोग करके अपना कोड जांचें । यह अक्सर आपको सही उत्तर देगा। इस स्थिति में SC2207 एक फाइल को पढ़ने को कवर करता है, जिसमें या तो स्पेस अलग हो जाता है या एक सरणी में न्यूलाइन से अलग वैल्यू।

यह मत करो

array=( $(mycommand) )

मानों के साथ फ़ाइलें newlines द्वारा अलग

mapfile -t array < <(mycommand)

रिक्त स्थान से अलग मूल्यों के साथ फाइलें

IFS=" " read -r -a array <<< "$(mycommand)"

शेलचेक पृष्ठ आपको तर्क देगा कि यह सबसे अच्छा अभ्यास क्यों माना जाता है।


0

यह उत्तर उपयोग करने के लिए कहता है

mapfile -t myArray < file.txt

मैं एक बनाया शिम के लिए mapfileआप उपयोग करना चाहते हैं mapfileबैश <जो भी कारण के लिए 4.x पर। mapfileयदि आप bash> = 4.x पर हैं, तो यह मौजूदा कमांड का उपयोग करता है

वर्तमान में, केवल विकल्प -dऔर -tकाम। लेकिन उस आदेश के लिए पर्याप्त होना चाहिए। मैंने केवल macOS पर परीक्षण किया है। MacOS सिएरा 10.12.6 पर, सिस्टम बैश है 3.2.57(1)-release। तो शिम काम आ सकता है। तुम भी बस अपने घर के साथ बैश को अपडेट कर सकते हैं, अपने आप को बैश बना सकते हैं, आदि।

यह एक कॉल स्टैक अप चर सेट करने के लिए इस तकनीक का उपयोग करता है ।

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