পাইথনে বাশ 'উত্স' অনুকরণ করে


92

আমার কাছে একটি স্ক্রিপ্ট রয়েছে যা দেখতে এরকম কিছু দেখাচ্ছে:

export foo=/tmp/foo                                          
export bar=/tmp/bar

আমি যখনই নির্মাণ করি তখনই আমি কিছু ভেরিয়েবল সেট আপ করতে 'উত্স আরম্ভ_এনভ' (যেখানে init_env উপরের স্ক্রিপ্টটি) চালিত করি।

পাইথনে এটি সম্পাদন করার জন্য আমার এই কোডটি চালু ছিল,

reg = re.compile('export (?P<name>\w+)(\=(?P<value>.+))*')
for line in open(file):
    m = reg.match(line)
    if m:
        name = m.group('name')
        value = ''
        if m.group('value'):
            value = m.group('value')
        os.putenv(name, value)

তবে তখন কেউ সিদ্ধান্ত নিয়েছে যে init_envফাইলে নীচের মতো একটি লাইন যুক্ত করা ভাল হবে:

export PATH="/foo/bar:/bar/foo:$PATH"     

স্পষ্টতই আমার পাইথনের লিপিটি আলাদা হয়ে গেল। আমি এই লাইনটি হ্যান্ডেল করার জন্য পাইথন স্ক্রিপ্টটি সংশোধন করতে পারি, তবে ফাইলটি ব্যবহার করার জন্য কেউ নতুন বৈশিষ্ট্য নিয়ে আসে তখনই এটি পরে যায় init_env

প্রশ্নটি হ'ল যদি কোনও বাশ কমান্ড চালানোর কোনও সহজ উপায় থাকে এবং এটি আমার পরিবর্তন করতে দেয় os.environ?


উত্তর:


109

আপনার পদ্ধতির সাথে সমস্যা হ'ল আপনি বাশ স্ক্রিপ্টগুলি ব্যাখ্যা করার চেষ্টা করছেন। প্রথমে আপনি কেবল এক্সপোর্ট স্টেটমেন্টটি ব্যাখ্যা করার চেষ্টা করুন। তারপরে আপনি লক্ষ্য করেছেন যে লোকেরা পরিবর্তনশীল প্রসার ব্যবহার করছে। পরে লোকেরা তাদের ফাইলগুলিতে শর্তযুক্ত বা বিকল্পগুলি প্রক্রিয়া করবে। শেষ অবধি আপনার গ্যাজিলিয়ন বাগ সহ একটি সম্পূর্ণ ফুলে উঠা বাশ স্ক্রিপ্ট ইন্টারপ্রেটার থাকবে। এটা করবেন না।

বাশ আপনার জন্য ফাইলটি ব্যাখ্যা করুন এবং তারপরে ফলাফল সংগ্রহ করুন।

আপনি এটি এর মতো করতে পারেন:

#! /usr/bin/env python

import os
import pprint
import shlex
import subprocess

command = shlex.split("env -i bash -c 'source init_env && env'")
proc = subprocess.Popen(command, stdout = subprocess.PIPE)
for line in proc.stdout:
  (key, _, value) = line.partition("=")
  os.environ[key] = value
proc.communicate()

pprint.pprint(dict(os.environ))

নিশ্চিত হয়ে নিন যে আপনি বাশ ব্যর্থ হতে ব্যর্থ হয়েছে source init_envবা ব্যাশ নিজেই কার্যকর করতে ব্যর্থ হয়েছে বা সাবপ্রসেস ব্যাশ কার্যকর করতে ব্যর্থ হয়েছে বা অন্য কোনও ত্রুটি রয়েছে Make

env -iকমান্ড লাইন শুরুতে একটি পরিচ্ছন্ন পরিবেশ সৃষ্টি করে। এর অর্থ আপনি কেবল পরিবেশের পরিবর্তনশীলগুলি থেকে পাবেন init_env। যদি আপনি উত্তরাধিকারসূত্রে সিস্টেম পরিবেশ চান তবে বাদ দিন env -i

আরও বিশদের জন্য সাবপ্রসেসে ডকুমেন্টেশন পড়ুন ।

দ্রষ্টব্য: এটি কেবল রফতানি ভেরিয়েবলগুলি মুদ্রণের সাথে সাথে কেবলমাত্র exportবিবৃতিটির সাথে সেট করা ভেরিয়েবলগুলি ক্যাপচার করবে env

উপভোগ করুন

নোট করুন পাইথন ডকুমেন্টেশন বলছে যে আপনি যদি পরিবেশটি পরিচালনা করতে চান তবে আপনার os.environব্যবহারের পরিবর্তে সরাসরি ম্যানিপুলেট করা উচিত os.putenv()। আমি যে একটি বাগ বিবেচনা, কিন্তু আমি digress।


12
আপনি যদি অ-রফতানি ভেরিয়েবলগুলি সম্পর্কে যত্নশীল হন এবং স্ক্রিপ্টটি আপনার নিয়ন্ত্রণের বাইরে থাকে তবে আপনি সমস্ত পরিবর্তনশীলকে রফতানি হিসাবে চিহ্নিত করতে সেট -a ব্যবহার করতে পারেন। শুধু কমান্ড পরিবর্তন করুন: [ 'ব্যাশ', '-c', 'সেট -a && উৎস init_env && env']
Ahal

দ্রষ্টব্য যে এটি রফতানি কার্যগুলিতে ব্যর্থ হবে। আমি যদি আপনার উত্তরটি পার্সিং দেখাচ্ছে যা ফাংশনগুলির জন্যও কাজ করে তা আপডেট করতে পারলে আমি এটি পছন্দ করব। (যেমন ফাংশন এফএফ () cho প্রতিধ্বনি "এফএফ"; export; এক্সপোর্ট-এফ এফএফ)
ডিএ

4
দ্রষ্টব্য: এটি মাল্টলাইন এনভায়রনমেন্ট ভেরিয়েবলগুলি সমর্থন করে না।
বেনসি

4
আমার ক্ষেত্রে, উপর iterating proc.stdout()উৎপাদনের বাইট, এইভাবে আমি পেয়ে ছিল TypeErrorউপর line.partition()line.decode().partition("=")সমস্যার সমাধানের সাথে স্ট্রিংয়ে রূপান্তর করা ।
স্যাম এফ

4
এটি অত্যন্ত সহায়ক ছিল। আমি ['env', '-i', 'bash', '-c', 'source .bashrc && env']নিজেকে আরসি ফাইল দ্বারা পরিবেশিত শুধুমাত্র পরিবেশের ভেরিয়েবলগুলি দেওয়ার জন্য নির্বাহ করেছি
xaviersjs

32

আচার ব্যবহার:

import os, pickle
# For clarity, I moved this string out of the command
source = 'source init_env'
dump = '/usr/bin/python -c "import os,pickle;print pickle.dumps(os.environ)"'
penv = os.popen('%s && %s' %(source,dump))
env = pickle.loads(penv.read())
os.environ = env

আপডেট হয়েছে:

এটি json, সাবপ্রসেস এবং স্পষ্টভাবে / বিন / ব্যাশ ব্যবহার করে (উবুন্টু সমর্থনের জন্য):

import os, subprocess as sp, json
source = 'source init_env'
dump = '/usr/bin/python -c "import os, json;print json.dumps(dict(os.environ))"'
pipe = sp.Popen(['/bin/bash', '-c', '%s && %s' %(source,dump)], stdout=sp.PIPE)
env = json.loads(pipe.stdout.read())
os.environ = env

উবুন্টুতে এটির একটি সমস্যা রয়েছে - সেখানে ডিফল্ট শেল রয়েছে /bin/dash, যা sourceকমান্ডটি জানে না । উবুন্টুতে এটি ব্যবহার করতে, আপনাকে /bin/bashস্পষ্টভাবে চালাতে হবে , উদাহরণস্বরূপ ব্যবহার করে penv = subprocess.Popen(['/bin/bash', '-c', '%s && %s' %(source,dump)], stdout=subprocess.PIPE).stdout(এটি নতুন subprocessমডিউলটি ব্যবহার করে যা আমদানি করতে হয়)।
মার্টিন পেকা

22

আপনার পাইথন স্ক্রিপ্টটি বাশ স্ক্রিপ্টটি উত্সের পরিবর্তে মোড়ক স্ক্রিপ্টের উত্স থাকা init_envএবং তারপরে পরিবর্তিত পরিবেশের সাথে আপনার পাইথন স্ক্রিপ্টটি চালানো সহজ এবং আরও মার্জিত হবে ।

#!/bin/bash
source init_env
/run/python/script.py

4
এটি কিছু পরিস্থিতিতে সমস্যাটি সমাধান করতে পারে তবে তাদের সবকটিই নয়। উদাহরণস্বরূপ, আমি একটি অজগর স্ক্রিপ্ট লিখছি যা ফাইলটি সোসারি করার মতো কিছু করতে হবে (আসলে আমি মডিউলগুলি কী লোড করছি তা যদি আপনি জানেন তবে) এবং এটি কিছু পরিস্থিতিতে নির্ভর করে একটি আলাদা মডিউল লোড করতে হবে । সুতরাং এটি আমার সমস্যার মোটেও সমাধান করবে না
ডেভিড

এটি বেশিরভাগ ক্ষেত্রে প্রশ্নের উত্তর দেয় এবং আমি যেখানেই সম্ভব এটি ব্যবহার করব। প্রদত্ত প্রকল্পের জন্য আমার আইডিইতে এই কাজটি করতে বেশ কষ্ট হয়েছিল। পরিবেশের সাথে একটি শেলের মধ্যে পুরো জিনিসটি চালানো একটি সম্ভাব্য পরিবর্তন হতে পারেbash --rcfile init_env -c ./script.py
xaviersjs

6

আপডেট করা হয়েছে @ ব্যবহারের জন্য পাইথন 3. নোটিশ lesmana এর উত্তর env -iযা সেট / পুনরায় সেট হওয়া থেকে বিদেশী বিভিন্ন পরিবেশের বাধা দেয় (সম্ভাব্য ভুল একাধিক লাইন env ভেরিয়েবলের জন্য হ্যান্ডলিং অভাব দেওয়া)।

import os, subprocess
if os.path.isfile("init_env"):
    command = 'env -i sh -c "source init_env && env"'
    for line in subprocess.getoutput(command).split("\n"):
        key, value = line.split("=")
        os.environ[key]= value

এটি ব্যবহার করা আমাকে "PATH: অপরিজ্ঞাত পরিবর্তনশীল" দেয় কারণ env -i পথ আনসেট করে। কিন্তু env -i ছাড়া এটি কাজ করে। এছাড়াও সাবধান থাকুন যে লাইনে একাধিক '=' থাকতে পারে
ফুজি

5

ফাংশনে @ ব্রায়ানের দুর্দান্ত উত্তর মোড়ানো উদাহরণ:

import json
import subprocess

# returns a dictionary of the environment variables resulting from sourcing a file
def env_from_sourcing(file_to_source_path, include_unexported_variables=False):
    source = '%ssource %s' % ("set -a && " if include_unexported_variables else "", file_to_source_path)
    dump = '/usr/bin/python -c "import os, json; print json.dumps(dict(os.environ))"'
    pipe = subprocess.Popen(['/bin/bash', '-c', '%s && %s' % (source, dump)], stdout=subprocess.PIPE)
    return json.loads(pipe.stdout.read())

আমি এই ইউটিলিটি ফাংশনটি অ্যাডস শংসাপত্র এবং ডকার। এনভি ফাইলগুলির সাথে পড়তে ব্যবহার করছি include_unexported_variables=True

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.