फाइल की तर्ज पर लूप कैसे करें?


61

कहो कि मेरे पास यह फाइल है:

hello
world
hello world

यह कार्यक्रम

#!/bin/bash

for i in $(cat $1); do
    echo "tester: $i"
done

आउटपुट

tester: hello
tester: world
tester: hello
tester: world

मैं forव्यक्तिगत रूप से व्हाट्सएप को अनदेखा करते हुए प्रत्येक पंक्ति पर पुनरावृति करना चाहता हूं , हालांकि अंतिम दो पंक्तियों को प्रतिस्थापित किया जाना चाहिए

tester: hello world

एक ही बार में पूरी फ़ाइल असाइन किए जाने पर उद्धरण for i in "$(cat $1)";परिणामों का उपयोग करना i। मुझे क्या बदलना चाहिए?

जवाबों:


69

forऔर IFS के साथ :

#!/bin/bash

IFS=$'\n'       # make newlines the only separator
set -f          # disable globbing
for i in $(cat < "$1"); do
  echo "tester: $i"
done

ध्यान दें कि यह खाली लाइनों को छोड़ देगा क्योंकि newline एक IFS-white-space वर्ण होता है, इसके क्रम को 1 के रूप में गिना जाता है और अग्रणी और अनुगामी को अनदेखा किया जाता है। साथ zshऔर ksh93(नहीं bash), आप इसे करने के लिए बदल सकते हैं IFS=$'\n\n'न्यू लाइन विशेष रूप से इलाज किया जा करने के लिए नहीं के लिए, फिर भी ध्यान दें कि सभी अनुगामी न्यू लाइन वर्ण (ताकि खाली लाइनों अनुगामी भी शामिल है) हमेशा आदेश प्रतिस्थापन द्वारा हटा दिया जाएगा।

या साथread (कोई और अधिक cat):

#!/bin/bash

while IFS= read -r line; do
  echo "tester: $line"
done < "$1"

वहां, खाली लाइनों को संरक्षित किया जाता है, लेकिन ध्यान दें कि यह अंतिम पंक्ति को छोड़ देगा यदि यह एक नई लाइन वर्ण द्वारा ठीक से सीमांकित नहीं किया गया था।


5
धन्यवाद, मुझे नहीं पता था कि <एक पूरे लूप में जा सकता है । हालांकि यह पूरी तरह से समझ में आता है अब मैंने इसे देखा
टोबियास किन्ज़लर

1
मुझे IFS \ read -r line' in second example. Is really IFS = `की आवश्यकता है? IMHO कहने के लिए यह पर्याप्त है:while read -r line; do echo "tester: $line"; done < "$1"
ग्रेजेगोरज़ वियर्ज़ोवेकी

4
@GrzegorzWierzowiecki IFS=अग्रणी और अनुगामी व्हॉट्सएप की स्ट्रिपिंग को बंद कर देता है। देखें में while IFS= read..है, क्यों आईएफएस कोई असर नहीं करता है?
गाइल्स

0

इसके लायक होने के लिए, मुझे ऐसा करने की आवश्यकता है, और इसका उपयोग करने का सही तरीका कभी भी याद नहीं रख सकता है while IFS= read..., इसलिए मैंने अपने bash प्रोफाइल में निम्नलिखित फ़ंक्शन को परिभाषित किया है:

# iterate the line of a file and call input function
iterlines() {
    (( $# < 2 )) && { echo "Usage: iterlines <File> <Callback>"; return; }
    local File=$1
    local Func=$2
    n=$(cat "$File" | wc -l)
    for (( i=1; i<=n; i++ )); do
        "$Func" "$(sed "${i}q;d" "$File")"
    done
}

यह फ़ंक्शन पहले फ़ाइल में लाइनों की संख्या निर्धारित करता है, फिर sedलाइन के बाद लाइन निकालने के लिए उपयोग करता है, और प्रत्येक लाइन को किसी भी फ़ंक्शन के लिए एकल स्ट्रिंग तर्क के रूप में पास करता है। मुझे लगता है कि यह बड़ी फ़ाइलों के साथ वास्तव में अक्षम हो सकता है, लेकिन यह मेरे लिए अब तक एक समस्या नहीं है (इस पाठ्यक्रम के स्वागत में सुधार करने के बारे में सुझाव)।

उपयोग बहुत प्यारा है IMO:

>> cat example.txt # note the use of spaces, whitespace, etc.
a/path

This is a sentence.
"wi\th quotes"
$End
>> iterlines example.txt echo # preserves quotes, $ and whitespace
a/path

This is a sentence.
"wi\th quotes"
$End
>> x() { echo "$#"; }; iterlines example.txt x # line always passed as single input string
1
1 
1
1
1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.