2009-04-27 5 views
15

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

मुझे बैश स्क्रिप्टिंग के साथ बहुत अधिक अनुभव नहीं है। मुझे विश्वास है कि पैरामीटर में रिक्त स्थान की अनुमति देने के लिए मुझे अपने चर को सही तरीके से उद्धृत करने में समस्याएं हैं। स्क्रिप्ट इस प्रकार है:

विभाजन: "foo/2009-04-27T14-32-04.backup" आ: ऐसा कोई फ़ाइल या निर्देशिका

#! /bin/bash 

# This script tars the given directory, encrypts it, and transfers 
# it to the given directory (likely a USB key). 

if [ $# -ne 2 ] 
then 
    echo "Usage: `basename $0` DIRECTORY BACKUP_DIRECTORY" 
    exit 1 
fi 

DIRECTORY=$1 
BACKUP_DIRECTORY=$2 
BACKUP_FILE="$BACKUP_DIRECTORY/`date +%Y-%m-%dT%H-%M-%S.backup`" 

TAR_CMD="tar cv $DIRECTORY" 
SPLIT_CMD="split -b 1024m - \"$BACKUP_FILE\"" 

ENCRYPT_CMD='openssl des3 -salt' 

echo "$TAR_CMD | $ENCRYPT_CMD | $SPLIT_CMD" 

$TAR_CMD | $ENCRYPT_CMD | $SPLIT_CMD 

say "Done backing up" 

इस आदेश चल रहा है के साथ विफल

मैं $BACKUP_FILE के आसपास उद्धरणों को हटाकर इसे ठीक कर सकता हूं जहां मैंने $SPLIT_CMD सेट किया था। लेकिन, अगर मेरे पास बैकअप निर्देशिका के नाम पर कोई स्थान है तो यह काम नहीं करता है। साथ ही, अगर मैं आउटपुट को "echo" कमांड से सीधे टर्मिनल में कॉपी और पेस्ट करता हूं तो यह ठीक काम करता है। स्पष्ट रूप से ऐसा कुछ है जो मुझे समझ में नहीं आता कि बैश चीजों से कैसे बच रहा है।

+0

क्यों आप $ BACKUP_FILE SPLIT_CMD में एम्बेड हैं जब आप बस इसे डाल सकता है के बाद टी में $ SPLIT_CMD वह पाइपलाइन? –

+0

वैसे मैं ऐसा कर सकता था, लेकिन उस समय मेरे आदेशों को रखने के लिए चर होने में वास्तव में बहुत अधिक बिंदु नहीं है और मैं इसे जूलियानो के उत्तर के रूप में भी विस्तारित कर सकता हूं। – wxs

+0

http://mywiki.wooledge.org/BashFAQ/050 – tripleee

उत्तर

35

बस पूर्ण आदेशों को चर में नहीं डालें। उद्धृत तर्कों को पुनर्प्राप्त करने का प्रयास करने में आपको बहुत सारी परेशानी होगी।

इसके अलावा

:

  1. बचें सभी राजधानियों लिपियों में चर नाम का उपयोग करते हुए। पैर पर खुद को शूट करने का आसान तरीका।
  2. बैकक्वॉट्स का उपयोग न करें, इसके बजाय $ (...) का उपयोग करें, यह बेहतर प्रदर्शन करता है।

#! /bin/bash 

if [ $# -ne 2 ] 
then 
    echo "Usage: $(basename $0) DIRECTORY BACKUP_DIRECTORY" 
    exit 1 
fi 

directory=$1 
backup_directory=$2 
current_date=$(date +%Y-%m-%dT%H-%M-%S) 
backup_file="${backup_directory}/${current_date}.backup" 

tar cv "$directory" | openssl des3 -salt | split -b 1024m - "$backup_file" 
+0

हाँ मुझे लगता है कि मैं शायद इसे इस तरह से करूँगा। चरों में आदेश रखने से मेरे लिए कम सुरुचिपूर्ण लगता है, लेकिन मुझे लगता है कि यह बैश स्क्रिप्टिंग की प्रकृति है। – wxs

+4

@wxs: चरों में कमांड डालने के बारे में कुछ भी सुरुचिपूर्ण नहीं है। आपको किसी प्रकार की लचीलापन नहीं मिलती है; इसके विपरीत, आप शब्द विभाजन के कारण बस बग का कारण बनते हैं। आप जो करना चाहते हैं वह कार्यों में कमांड डालता है। आप कार्य निष्पादित करते हैं। आपको चर सामग्री को निष्पादित नहीं करना चाहिए। कभी। – lhunath

+7

मुझे समझ में नहीं आता 1. समझाने की देखभाल? पैर में खुद को शूट करना क्यों आसान बनाता है? – ata

5

मुझे यकीन नहीं है, लेकिन यह पहले आदेशों पर एक eval चलाने लायक हो सकता है।

यह बैश इस तरह अपनी पूरी चौड़ाई के चर $ TAR_CMD और विस्तार करने देगा

बैश तो लाइन के साथ दूसरी बार दिखाया जाएगा (गूंज आदेश कंसोल, जो आप कहते हैं कि काम करता है के लिए करता है बस के रूप में) चर विस्तारित।

eval $TAR_CMD | $ENCRYPT_CMD | $SPLIT_CMD 

मैंने अभी Google खोज की है और यह पृष्ठ ऐसा लगता है कि यह क्यों जरूरी है कि यह क्यों एक सभ्य नौकरी कर सकता है। http://fvue.nl/wiki/Bash:_Why_use_eval_with_variable_expansion%3F

+0

ऐसा लगता है कि यह भी ऐसा लगता है, लेकिन मुझे लगता है कि यह सबकुछ थोड़ा गड़बड़ कर देता है। ओह ठीक है, मैं देखता हूं कि लोगों ने अन्य स्क्रिप्टिंग भाषाओं का आविष्कार क्यों किया। – wxs

+0

यह एक बड़ा सुरक्षा जोखिम है। सर्वोत्तम अभ्यास विकल्प के लिए BashFAQ # 50 देखें: http:// evwiki.wooledge.org/BashFAQ/050 - और BashFAQ # 48 के विवरण के लिए 'eval' जोखिम क्यों लेता है: http://mywiki.wooledge.org/BashFAQ/048 –

+0

अच्छी पकड़ @ चार्ल्सडफी, अगर इसका उपयोग किसी साझा सिस्टम पर किया जा रहा है जहां अन्य उपयोगकर्ताओं को उच्च अधिकारों के साथ चलाने के लिए स्क्रिप्ट तक पहुंच प्रदान की जाती है, तो यह एक जोखिम है। – Eddie

1

चर ऐसी है कि खोल बातें फिर से व्याख्या करेगा अंदर रिक्त स्थान का हवाला देते हुए ठीक से कठिन है। यह इस तरह की चीज है जो मुझे एक मजबूत भाषा तक पहुंचने के लिए प्रेरित करती है। चाहे वह पर्ल या पायथन या रूबी या जो भी हो (मैं पर्ल चुनता हूं, लेकिन यह हमेशा के लिए नहीं है), यह सिर्फ कुछ है जो आपको उद्धरण के लिए खोल को बाईपास करने की अनुमति देगा।

ऐसा नहीं है कि मैंने कभी भी उदारता की उदार खुराक के साथ इसे सही करने में कामयाब नहीं रहा है, लेकिन केवल उस eval मुझे ईबे-जीबी देता है (जब आप उपयोगकर्ता इनपुट लेना चाहते हैं और इसे eval, तो एक नया सिरदर्द बन जाता है, हालांकि इस मामले में आप जो सामान लिखे थे और उसे इसके बजाय तैयार कर रहे थे), और मुझे डिबगिंग में सिरदर्द मिल गया है।- लेकिन IO::Pipe, कांटा का एक सा है, और stdout और stderr फिर से खोलने

@tar_cmd = (qw(tar cv), $directory); 
@encrypt_cmd = (qw(openssl des3 -salt)); 
@split_cmd = (qw(split -b 1024m -), $backup_file); 

कठिन हिस्सा यहाँ पाइप कर रही है:

पर्ल के साथ

, मेरे उदाहरण के रूप में, मैं की तरह कुछ करने के लिए सक्षम होगा , और यह बुरा नहीं है। कुछ लोग कहते हैं कि खोल को सही तरीके से उद्धृत करने से भी बदतर है, और मैं समझता हूं कि वे कहां से आ रहे हैं, लेकिन मेरे लिए, इसे पढ़ना, बनाए रखना और लिखना आसान है। बिल्ली, कोई इस से कड़ी मेहनत कर सकता है और आईओ :: पाइपलाइन मॉड्यूल बना सकता है और पूरी चीज को छोटा कर सकता है ;-)

+0

यदि आप 'eval' का उपयोग कर * इसे कठिन समस्या बनाते हैं तो यह केवल एक कठिन समस्या है। ऐसा करने का कोई अच्छा कारण नहीं है। –

4

केवल चरों में कमांड और विकल्प डालने का एक बिंदु है।

#! /bin/bash 

if [ $# -ne 2 ] 
then 
    echo "Usage: `basename $0` DIRECTORY BACKUP_DIRECTORY" 
    exit 1 
fi 

. standard_tools  

directory=$1 
backup_directory=$2 
current_date=$(date +%Y-%m-%dT%H-%M-%S) 
backup_file="${backup_directory}/${current_date}.backup" 

${tar_create} "${directory}" | ${openssl} | ${split_1024} "$backup_file" 

आप किसी अन्य फाइल आप स्रोत को आदेश स्थानांतरित कर सकते हैं, तो आप कई लिपियों में एक ही आदेश और विकल्प का पुन: उपयोग कर सकते हैं। यह बहुत आसान है जब आपके पास बहुत सारी स्क्रिप्ट हैं और आप यह नियंत्रित करना चाहते हैं कि वे सभी टूल का उपयोग कैसे करते हैं। तो standard_tools होते हैं:

export tar_create="tar cv" 
export openssl="openssl des3 -salt" 
export split_1024="split -b 1024m -" 
+0

'tar_create' गुम है लेकिन फिर भी –

+1

मदद मिली यह वास्तव में जटिल तर्कों के लिए समस्या का समाधान नहीं करता है। यदि आपका 'tar_create'' tar cv - exclude = "* *" था, तो यह मूल के समान ही असफल हो जाता। और 'निर्यात' यहां कुछ भी उपयोगी नहीं है - इन चरों का उपयोग एक ही खोल में किया जाता है, इसलिए प्रदूषण उपप्रोसेस की पर्यावरण की जगह बस एक अपशिष्ट है। –

5

eval एक स्वीकार्य अभ्यास अपने निर्देशिका नाम अविश्वस्त स्रोतों द्वारा उत्पन्न किया जा सकता है, अगर नहीं है। इस समस्या को और इसके समुचित समाधान, जिनमें से कुछ नीचे को छुआ कर रहे हैं के मूल कारण के बारे में अधिक के लिए क्यों eval नहीं किया जाना चाहिए के बारे में अधिक के लिए BashFAQ #48, और BashFAQ #50 देखें:

आप समय के साथ अपने आदेशों का निर्माण करने की जरूरत है , उपयोग सरणियों:

tar_cmd=(tar cv "$directory") 
split_cmd=(split -b 1024m - "$backup_file") 
encrypt_cmd=(openssl des3 -salt) 
"${tar_cmd[@]}" | "${encrypt_cmd[@]}" | "${split_cmd[@]}" 

वैकल्पिक रूप से, अगर यह सिर्फ एक केंद्रीय स्थान में अपने आदेश को परिभाषित करने के बारे में है, का उपयोग करें कार्य:

tar_cmd() { tar cv "$directory"; } 
split_cmd() { split -b 1024m - "$backup_file"; } 
encrypt_cmd() { openssl des3 -salt; } 
tar_cmd | split_cmd | encrypt_cmd 
संबंधित मुद्दे