শেল এর ভেরিয়েবলের মধ্যে একটি ফাইল কীভাবে পড়বেন?


488

আমি একটি ফাইল পড়তে এবং এটিকে ভেরিয়েবলে সংরক্ষণ করতে চাই, তবে আমার কেবল পরিবর্তনশীল রাখা দরকার এবং কেবল ফাইল মুদ্রণ করা উচিত নয়। কিভাবে আমি এটি করতে পারব? আমি এই স্ক্রিপ্টটি লিখেছি তবে এটি আমার প্রয়োজনের মতো নয়:

#!/bin/sh
while read LINE  
do  
  echo $LINE  
done <$1  
echo 11111-----------  
echo $LINE  

আমার স্ক্রিপ্টে, আমি প্যারামিটার হিসাবে ফাইলের নাম দিতে পারি, সুতরাং, যদি ফাইলটিতে "আআআআ" থাকে, তবে এটি এটি মুদ্রণ করে:

aaaa
11111-----

তবে এটি কেবল স্ক্রিনে ফাইলটি প্রিন্ট করে, এবং আমি এটিকে পরিবর্তনশীল হিসাবে সংরক্ষণ করতে চাই! এটি করার কোনও সহজ উপায় আছে?


1
এটি একটি সরল পাঠ বলে মনে হচ্ছে। যদি একটি বাইনারি ফাইল ছিল, আপনি হবে এই এর ফলে catবা $(<someFile)একটি অসম্পূর্ণ আউটপুটে হবে (আকার বাস্তব ফাইল চেয়ে কম হয়)।
কুম্ভ শক্তি

উত্তর:


1052

ক্রস প্ল্যাটফর্মে, shআপনি ব্যবহার করেন সর্বনিম্ন-সাধারণ-ডিনোমিনেটর :

#!/bin/sh
value=`cat config.txt`
echo "$value"

ইন bashবা zsh, invoking ছাড়া একটি পরিবর্তনশীল মধ্যে একটি পুরো ফাইলটি পড়ার cat:

#!/bin/bash
value=$(<config.txt)
echo "$value"

কোনও ফাইল চালু করা বা স্লুর্প catকরা বিড়ালের অকেজো ব্যবহার হিসাবে বিবেচিত হবে ।bashzsh

মনে রাখবেন যে নতুন লাইনগুলি সংরক্ষণের জন্য কমান্ড প্রতিস্থাপনের উদ্ধৃতি দেওয়া দরকার নেই।

দেখুন: বাশ হ্যাকারের উইকি - কমান্ড প্রতিস্থাপন - বিশেষত্ব


4
ঠিক আছে তবে এটি বাশ, শ নয়; এটি সব ক্ষেত্রে মাপসই করা যায় না।
মোয়ালা

14
কনফিগ টেক্সট-এ স্পেস রয়েছে সে ক্ষেত্রে value="`cat config.txt`"এবং value="$(<config.txt)"নিরাপদ হবে না ?
মার্টিন ভন উইটিচ

13
নোট করুন যে catউপরে হিসাবে ব্যবহার করা সর্বদা অকেজো ব্যবহার হিসাবে বিবেচিত হয় না cat। উদাহরণস্বরূপ, < invalid-file 2>/dev/nullএমন একটি ত্রুটি বার্তায় পরিণত হবে যা রুটে যেতে পারে না /dev/null, যেখানে cat invalid-file 2>/dev/nullসঠিকভাবে রুটে যায় /dev/null
দেজয় ক্লেটন

16
আমার মতো নতুন শেল স্ক্রিপ্টারের জন্য, বিড়ালের সংস্করণটি টিকিটগুলি ব্যবহার করে, একক উদ্ধৃতি নয় নোট করুন! আশা করি এটি কারও আধা ঘন্টা সাশ্রয় পাবে এটি বের করতে আমার সময় লেগেছে।
এরিকসোনলা

7
আমার মতো নতুন বাশারদের জন্য: নোটটি value=$(<config.txt)ভাল, তবে value = $(<config.txt)খারাপ। এই স্পেসগুলির জন্য সতর্কতা অবলম্বন করুন।
আর্টহেয়ার

88

আপনি যদি পুরো ফাইলটি ভেরিয়েবলের মধ্যে পড়তে চান তবে:

#!/bin/bash
value=`cat sources.xml`
echo $value

আপনি যদি এটি লাইন বাই লাইন পড়তে চান তবে:

while read line; do    
    echo $line    
done < file.txt

2
@ ব্রেন: ফাইলটি যদি কনফিগার্ড পিপি হয় এবং এতে ব্যাকস্ল্যাশ থাকে; ডাবল উক্তি এবং উদ্ধৃতি?
ব্যবহারকারী 2284570

2
আপনার চলকটি ডাবল-কোট করা উচিত echo "$value"। অন্যথায়, শেলটি মানের সাথে সাদা স্থান টোকেনাইজেশন এবং ওয়াইল্ডকার্ড সম্প্রসারণ করবে।
ট্রিপলি

3
@ ব্যবহারকারী 2284570 ন্যায়বিচারের read -rপরিবর্তে readসর্বদা ব্যবহার করুন , যদি না আপনি নির্দিষ্টভাবে অদ্ভুত উত্তরাধিকার আচরণের প্রয়োজন যা আপনি নির্দেশ করছেন।
ট্রিপল

74

দুটি গুরুত্বপূর্ণ সমস্যা

যা এ পর্যন্ত অন্যান্য উত্তর দ্বারা উপেক্ষা করা হয়েছিল:

  1. কমান্ড সম্প্রসারণ থেকে নতুন লাইন অপসারণের অনুসরণ করা
  2. NUL চরিত্র অপসারণ

কমান্ড সম্প্রসারণ থেকে নতুন লাইন অপসারণের অনুসরণ করা

এটি এর জন্য একটি সমস্যা:

value="$(cat config.txt)"

টাইপ সমাধান, কিন্তু readভিত্তিক সমাধানের জন্য নয় ।

কমান্ড সম্প্রসারণ নতুন লাইনের লাইনগুলি সরিয়ে দেয়:

S="$(printf "a\n")"
printf "$S" | od -tx1

আউটপুট:

0000000 61
0000001

এটি ফাইলগুলি থেকে পড়ার নিষ্পাপ পদ্ধতিটি ভেঙে দেয়:

FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"

পসিক্স কার্যক্রমে: কমান্ড প্রসারণে একটি অতিরিক্ত চর যুক্ত করুন এবং এটি পরে সরিয়ে দিন:

S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1

আউটপুট:

0000000 61 0a 0a
0000003

প্রায় পসিক্স কার্যক্রমে: এএসসিআইআই এনকোড। নিচে দেখ.

NUL চরিত্র অপসারণ

ভেরিয়েবলগুলিতে NUL অক্ষর সংরক্ষণ করার কোনও বুদ্ধিমান বাশ উপায় নেই

এটি সম্প্রসারণ এবং readসমাধান উভয়কেই প্রভাবিত করে এবং আমি এর পক্ষে ভাল কোনও কার্যকারিতা জানি না।

উদাহরণ:

printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1

আউটপুট:

0000000 61 00 62
0000003

0000000 61 62
0000002

হা, আমাদের NUL চলে গেছে!

সমাধান নীচে উপস্থিত:

  • এএসসিআইআই এনকোড। নিচে দেখ.

  • ব্যাশ এক্সটেনশন $""আক্ষরিক ব্যবহার করুন :

    S=$"a\0b"
    printf "$S" | od -tx1

    কেবল আক্ষরিক জন্য কাজ করে তাই ফাইল থেকে পড়ার জন্য দরকারী নয়।

ক্ষতির জন্য একযোগে

ভেরিয়েবলটিতে ফাইলের একটি ইউউনকোড বেস 64 এনকোড সংস্করণ সংরক্ষণ করুন এবং প্রতিটি ব্যবহারের আগে ডিকোড করুন:

FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"

আউটপুট:

0000000 61 00 0a
0000003

uuencode এবং udecode হয় POSIX 7 কিন্তু উবুন্টু 12.04 এ ডিফল্ট (দ্বারা sharutilsপ্যাকেজ) ... আমি ব্যাশ প্রক্রিয়া কি POSIX 7 বিকল্প দেখতে পাচ্ছ<() প্রতিকল্পন এক্সটেনশন অন্য ফাইল লেখা ছাড়া ...

অবশ্যই, এটি ধীর এবং অসুবিধাগুলি, তাই আমি অনুমান করি আসল উত্তরটি হ'ল: ইনপুট ফাইলটিতে NUL অক্ষর থাকতে পারে তবে ব্যাশ ব্যবহার করবেন না।


2
ধন্যবাদ শুধুমাত্র এই আমার জন্য কাজ করেছে কারণ আমার নতুন লাইনের দরকার ছিল।
জেসন লাইভসে

1
@ সিরোস্যান্টিলি: ফাইল যদি কনফিগারেশন পিপি হয় এবং এতে ব্যাকস্ল্যাশ থাকে তবে কী হবে; ডাবল উক্তি এবং উদ্ধৃতি?
ব্যবহারকারী 2284570

@ user2284570 আমি জানতাম না, কিন্তু এটা খুঁজে বের করতে সহজ: S="$(printf "\\\'\"")"; echo $S। আউটপুট: \'"। সুতরাং এটি কাজ করে =)
সিরো সান্তিলি 法轮功 冠状 病 六四 事件 法轮功

@ সিরোসান্টেলি: 5511 লাইনে? আপনি কি নিশ্চিত যে কোনও স্বয়ংক্রিয় উপায় নেই?
ব্যবহারকারী 2284570

@ ব্যবহারকারী 2284570 আমি বুঝতে পারি না, 5511 লাইনগুলি কোথায় আছে? ক্ষতিগুলি $()প্রসারণ থেকে আসে , আমার উদাহরণ দেখায় যে $()প্রসারণটি কাজ করে \'"
সিরো সান্তিলি 郝海东 冠状 病 六四 事件 法轮功


2

হিসাবে সিরো Santilli নোট কমান্ড বদল ব্যবহার trailing নতুন লাইন ড্রপ করবে। তাদের অনুশীলনকারী চরিত্রগুলি যোগ করার কাজটি দুর্দান্ত, তবে বেশ কিছু সময়ের জন্য এটি ব্যবহার করার পরে আমি স্থির করেছিলাম যে আমার এমন একটি সমাধান দরকার যা কমান্ড সাবস্টিটিউশনটি মোটেও ব্যবহার না করে।

স্ট্রিনের বিষয়বস্তু সরাসরি কোনও ভেরিয়েবলে পড়ার জন্য আমার অ্যাপ্রোচটি এখন বিল্টিনের পতাকাread সহ ব্যবহার করে ।printf-v

# Reads stdin into a variable, accounting for trailing newlines. Avoids needing a subshell or
# command substitution.
read_input() {
  # Use unusual variable names to avoid colliding with a variable name
  # the user might pass in (notably "contents")
  : "${1:?Must provide a variable to read into}"
  if [[ "$1" == '_line' || "$1" == '_contents' ]]; then
    echo "Cannot store contents to $1, use a different name." >&2
    return 1
  fi

  local _line _contents
   while read -r _line; do
     _contents="${_contents}${_line}"$'\n'
   done
   _contents="${_contents}${_line}" # capture any content after the last newline
   printf -v "$1" '%s' "$_contents"
}

এটি নতুন লাইনের সাথে বা অনুসরণ ছাড়াই ইনপুটগুলিকে সমর্থন করে।

ব্যবহারের উদাহরণ:

$ read_input file_contents < /tmp/file
# $file_contents now contains the contents of /tmp/file

গ্রেট! আমি শুধু ভাবছি, _contents="${_contents}${_line}\n "নিউলাইনগুলি সংরক্ষণের মতো কিছু ব্যবহার করবেন না কেন ?
Eenoku

1
আপনি কি সম্পর্কে জিজ্ঞাসা করছেন $'\n'? এটি প্রয়োজনীয়, অন্যথায় আপনি আক্ষরিক \ এবং nঅক্ষর যুক্ত করছেন ending আপনার কোড ব্লকের শেষেও অতিরিক্ত জায়গা রয়েছে, এটি উদ্দেশ্যমূলক কিনা তা নিশ্চিত নন, তবে এটি পরবর্তী সাদাটে অতিরিক্ত শ্বেত স্থানের সাথে যুক্ত করা হবে।
dimo414

ঠিক আছে, ব্যাখ্যা জন্য আপনাকে ধন্যবাদ!
এএনোকু

-3

লুপের জন্য আপনি একবারে 1 টি লাইন অ্যাক্সেস করতে পারেন

#!/bin/bash -eu

#This script prints contents of /etc/passwd line by line

FILENAME='/etc/passwd'
I=0
for LN in $(cat $FILENAME)
do
    echo "Line number $((I++)) -->  $LN"
done

পুরো বিষয়বস্তু ফাইলটিতে অনুলিপি করুন (বলুন line.sh); এক্সিকিউট

chmod +x line.sh
./line.sh

আপনার forলুপটি লাইনগুলিতে লুপ করে না, এটি শব্দের উপরে লুপ করে। ক্ষেত্রে /etc/passwd, এটি ঘটে যে প্রতিটি লাইনে কেবল একটি শব্দ থাকে। তবে অন্যান্য ফাইলগুলিতে প্রতি লাইনে একাধিক শব্দ থাকতে পারে।
এমপিবি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.