संभवत: व्हॉट्सएप के साथ फाइलनाम की एक सूची के साथ काम करने का पॉसिक्स अनुपालन तरीका


14

मैंने बैश स्क्रिप्टिंग गाइड में व्हॉट्सएप वाले फाइलनाम के साथ काम करने के लिए सरणी के उपयोग का सुझाव दिया है। DashAsBinSh का सुझाव है कि सरणियाँ पोर्टेबल नहीं हैं, इसलिए मैं उन फ़ाइलनामों की सूचियों के साथ काम करने के POSIX अनुरूप तरीके की तलाश में हूं जिनमें व्हॉट्सएप हो सकता है।

मैं नीचे उदाहरण स्क्रिप्ट को संशोधित करने के लिए देख रहा हूं ताकि यह होगा echo

foo/target/a.jar
foo/target/b.jar
bar/target/lol whitespace.jar

यहाँ स्क्रिप्ट है

#!/usr/bin/env sh

INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"
# this would be produced by a 'ls' command
# We can execute the ls within the script, if it helps

dostuffwith() { echo $1; };

F_LOCATIONS=$INPUT
ALL_FILES=$(for f in $F_LOCATIONS; do echo `basename $f`; done)
ALL_FILES=$(echo "$ALL_FILES" | sort | uniq)

for f in $ALL_FILES
do
    fpath=$(echo "$F_LOCATIONS" | grep -m1 $f)
    dostuffwith $fpath
done

जवाबों:


8

POSIX गोले एक सरणी है: स्थितीय मानकों ( $1, $2आदि, सामूहिक रूप से करने के लिए संदर्भित "$@")।

set -- 'foo/target/a.jar' 'foo/target/b.jar' 'bar/target/b.jar' 'bar/target/lol whitespace.jar'
set -- "$@" '/another/one at the end.jar'

for jar do
  dostuffwith "$jar"
done

यह असुविधाजनक है क्योंकि केवल एक ही है, और यह स्थितिगत मापदंडों के किसी अन्य उपयोग को नष्ट कर देता है। पोजिशनल पैरामीटर एक फ़ंक्शन के लिए स्थानीय हैं, जो कभी-कभी एक आशीर्वाद और कभी-कभी एक अभिशाप होता है।

यदि आपके फ़ाइल नामों की गारंटी नहीं है कि आप नई सुर्खियों में नहीं हैं, तो आप विभाजक के रूप में नई पंक्तियों का उपयोग कर सकते हैं। जब आप वैरिएबल का विस्तार करते हैं, तो पहले ग्लोबिंग को बंद करें set -fऔर IFSकेवल एक नई पंक्ति में रखने के लिए फ़ील्ड विभाजन वर्णों की सूची सेट करें ।

INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"

set -f; IFS='
'                           # turn off variable value expansion except for splitting at newlines
for jar in $INPUT; do
  set +f; unset IFS
  dostuffwith "$jar"        # restore globbing and field splitting at all whitespace
done
set +f; unset IFS           # do it again in case $INPUT was empty

अपनी सूची में आइटमों को नई सूचियों से अलग करके, आप विशेष रूप से उपयोगी कई टेक्स्ट प्रोसेसिंग कमांड का उपयोग कर सकते हैं sort

चर प्रतिस्थापन के आसपास हमेशा दोहरे उद्धरण देना याद रखें, सिवाय इसके कि जब आप स्पष्ट रूप से फ़ील्ड विभाजन (साथ ही ग्लोबिंग करना चाहते हैं, जब तक कि आप उस बंद नहीं हो जाते)।


अच्छा जवाब और स्पष्टीकरण। मैं इसे इस रूप में स्वीकार करने जा रहा हूं क्योंकि यह मूल sort | uniqचरण को इच्छानुसार काम करता है।
Eero Aaltonen

5

चूँकि आपका $INPUTवैरिएबल विभाजकों के रूप में नईलाइन्स का उपयोग करता है, इसलिए मैं यह मानने जा रहा हूँ कि आपकी फ़ाइलों के नामों में नईलाइन नहीं होगी। जैसे, हां, फाइलों पर निगरानी करने और व्हॉट्सएप को संरक्षित करने का एक सरल तरीका है।

readशेल बिलिन का उपयोग करने का विचार है । आम तौर readपर किसी भी व्हाट्सएप पर विभाजित हो जाएगा, और इसलिए रिक्त स्थान इसे तोड़ देंगे। लेकिन आप सेट कर सकते हैं IFS=$'\n'और यह केवल newlines पर विभाजित होगा। तो आप अपनी सूची में प्रत्येक पंक्ति पर पुनरावृति कर सकते हैं।

यहाँ सबसे छोटा समाधान है जो मैं आ सकता था:

INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"

dostuffwith() {
    echo "$1"
}

echo "$INPUT" | awk -F/ '{if (!seen[$NF]++) print }' | \
while IFS=$'\n' read file; do
  dostuffwith "$file"
done

मूल रूप से यह "$ INPUT" भेजता है, awkजिसमें फ़ाइल नाम के आधार पर कटौती की जाती है (यह विभाजन करता है /और फिर उस रेखा को प्रिंट करता है यदि अंतिम आइटम पहले नहीं देखा गया है)। फिर एक बार awk ने फ़ाइल पथों की सूची तैयार की है, हम while readसूची के माध्यम से पुनरावृति करने के लिए उपयोग करते हैं।


$ Checkbashisms bar.sh लाइन 14 (<<< यहाँ स्ट्रिंग) में संभव bashism bar.sh
ईरो Aaltonen

1
@EeroAaltonen ने हेस्टिंग्रिंग का उपयोग नहीं करने के लिए इसे बदल दिया। ध्यान दें कि इस परिवर्तन के साथ, whileलूप, और इस प्रकार dostuffwithएक सब-टाइम में निष्पादित किया जाता है। तो चल रहे शेल में किए गए किसी भी चर या परिवर्तन को लूप पूरा होने पर खो दिया जाएगा। एकमात्र विकल्प एक पूर्ण आनुवंशिकता का उपयोग करना है, जो कि अप्रिय नहीं है, लेकिन मुझे लगा कि यह बेहतर होगा।
पैट्रिक

मैं छोटेपन की तुलना में पठनीयता के आधार पर अधिक अंक प्रदान कर रहा हूं। यह निश्चित रूप से काम करता है और इसके लिए पहले से ही +1।
Eero Aaltonen

IFS="\n"बैकस्लैश और एन वर्णों पर विभाजन। लेकिन अंदर read file, कोई विभाजन नहीं है। IFS="\n"इसमें अभी भी उपयोगी है कि यह $ IFS से रिक्त वर्णों को हटा देता है जो अन्यथा इनपुट की शुरुआत और अंत में छीन लिया गया होता। एक पंक्ति को पढ़ने के लिए, विहित वाक्यविन्यास है IFS= read -r line, हालांकि IFS=anything read -r line(बशर्ते कुछ भी रिक्त न हो) भी काम करेगा।
स्टीफन चेज़लस

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