কাট বাশ দিয়ে কেন ব্যর্থ হয় এবং zsh না?


10

আমি ট্যাব-সীমাবদ্ধ ক্ষেত্রগুলি দিয়ে একটি ফাইল তৈরি করি।

echo foo$'\t'bar$'\t'baz$'\n'foo$'\t'bar$'\t'baz > input

আমি নীচের স্ক্রিপ্ট নাম আছে zsh.sh

#!/usr/bin/env zsh
while read line; do
    <<<$line cut -f 2
done < "$1"

আমি এটা পরীক্ষা।

$ ./zsh.sh input
bar
bar

এটি কাজ করে। যাইহোক, আমি পরিবর্তে যখন অনুরোধ করার জন্য প্রথম লাইনটি পরিবর্তন করি তখন bashএটি ব্যর্থ হয়।

$ ./bash.sh input
foo bar baz
foo bar baz

কেন এটি ব্যর্থ হয় bashএবং সাথে কাজ করে zsh?

অতিরিক্ত সমস্যা সমাধান

  • শেবাংয়ের পরিবর্তে সরাসরি পথ ব্যবহার করা envএকই আচরণের জন্ম দেয়।
  • echoএখানে স্ট্রিংটি ব্যবহার না করে পাইপিং করা <<<$lineএকই আচরণ তৈরি করে। অর্থাত echo $line | cut -f 2
  • ব্যবহার awkপরিবর্তে cut কাজ উভয় শাঁস জন্য। অর্থাত <<<$line awk '{print $2}'

4
যাইহোক, আপনি এই এক করে আরও সহজভাবে আপনার পরীক্ষা ফাইল বানান করতে পারেন: echo -e 'foo\tbar\tbaz\n...', echo $'foo\tbar\tbaz\n...', অথবা printf 'foo\tbar\tbaz\n...\n'বা এগুলোর বৈচিত্র। এটি প্রতিটি ট্যাব বা নিউলাইন স্বতন্ত্রভাবে মোড়ানো থেকে বাঁচায়।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

উত্তর:


13

যা ঘটে তা হ'ল bashস্থানগুলি দিয়ে ট্যাবগুলি প্রতিস্থাপন করে। "$line"পরিবর্তে বলে বা স্পষ্টত ফাঁকা জায়গা কেটে আপনি এই সমস্যাটি এড়াতে পারেন ।


1
বাশ \tএকটি স্থান দেখে এবং এটি একটি স্থান দিয়ে প্রতিস্থাপন করার কোনও কারণ আছে ?
ব্যবহারকারী 1717828

@ ব্যবহারকারী 1717828 হ্যাঁ, একে স্পিট + গ্লোব অপারেটর বলা হয় । আপনি যখন ব্যাশ এবং অনুরূপ শাঁসগুলিতে অনাবৃত একটি পরিবর্তনশীল ব্যবহার করেন তখন এটিই ঘটে।
টেরডন

1
@ ইটারডন, ইন <<< $line, bashবিভক্ত হয় তবে গ্লোব নয়। কোনও <<<একক শব্দের প্রত্যাশা হিসাবে এটি এখানে বিভক্ত হওয়ার কোনও কারণ নেই । এটি বিভক্ত হয়ে যায় এবং তারপরে সেই ক্ষেত্রে যোগ দেয়, যা সামান্য অর্থ দেয় এবং এর <<<আগে বা পরে সমর্থনকারী অন্যান্য সমস্ত শেল বাস্তবায়নের বিরুদ্ধে bash। আইএমও এটি একটি বাগ।
স্টাফেন চেজেলাস

@ স্টাফেনচেজেলাস যথেষ্ট মেলা, বিষয়টি যাইহোক বিভাজনের অংশ নিয়ে।
টেরডন

2
@

17

এর কারণ <<< $line, bashশব্দটি বিভাজন করে না (যদিও গ্লোব্বিং নয়) $lineকারণ এটি সেখানে উদ্ধৃত হয়নি এবং তারপরে স্পেস ক্যারেক্টারের সাথে ফলাফলগুলি শব্দের সাথে মিলিত হয় (এবং এটি একটি নতুন লাইনের চরিত্রের পরে একটি অস্থায়ী ফাইলে রাখে এবং যে স্টিডিন তৈরি করে cut)।

$ a=a,b,,c bash -c 'IFS=","; sed -n l <<< $a'
a b  c$

tabএর ডিফল্ট মান হতে পারে $IFS:

$ a=$'a\tb'  bash -c 'sed -n l <<< $a'
a b$

সমাধানটি bashহল ভেরিয়েবলের উদ্ধৃতি দেওয়া ote

$ a=$'a\tb' bash -c 'sed -n l <<< "$a"'
a\tb$

মনে রাখবেন এটি একমাত্র শেল যা এটি করে। zsh(যেখানে <<<ইউনিক্স বন্দর দ্বারা অনুপ্রাণিত হয়ে এসেছে rc) ksh93, mkshএবং yashযা এটিকে সমর্থন করে <<<না সেগুলিও এটি করে না।

এটা অ্যারে বিষয় আসে, তখন mksh, yashএবং zshপ্রথম অক্ষরটি এ যোগ $IFS, bashএবং ksh93স্থান।

$ mksh -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1:2$
$ yash -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1:2$
$ ksh -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1 2$
$ zsh -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1:2$
$ bash -c 'a=(1 2); IFS=:; sed -n l <<< "${a[@]}"'
1 2$

শূন্য থাকা অবস্থায় zsh/ yashএবং mksh(কমপক্ষে সংস্করণ R52) এর মধ্যে পার্থক্য রয়েছে $IFS:

$ mksh -c 'a=(1 2); IFS=; sed -n l <<< "${a[@]}"'
1 2$
$ zsh -c 'a=(1 2); IFS=; sed -n l <<< "${a[@]}"'
12$

আপনি ব্যবহার করার সময় শেলগুলি জুড়ে আচরণটি আরও সুসংগত হয় "${a[*]}"( খালি থাকা mkshঅবস্থায় এখনও একটি বাগ থাকে $IFS)।

ইন echo $line | ..., এটি সমস্ত বোর্নের মতো শেলগুলির মধ্যে সাধারণ স্প্লিট + গ্লোব অপারেটর তবে zsh(এবং এর সাথে জড়িত স্বাভাবিক সমস্যাগুলি echo)।


1
দুর্দান্ত উত্তর! ধন্যবাদ (+1) আমি সর্বনিম্ন rep'ed প্রশ্নকর্তাকে যদিও গ্রহণ করব, যেহেতু তারা আমার মূর্খতা প্রকাশের জন্য যথাযথভাবে প্রশ্নের উত্তর দিয়েছিল।
স্পারহাক

10

সমস্যাটি হ'ল আপনি উদ্ধৃতি দিচ্ছেন না $line। তদন্ত করতে, দুটি স্ক্রিপ্ট পরিবর্তন করুন যাতে তারা কেবল মুদ্রণ করে $line:

#!/usr/bin/env bash
while read line; do
    echo $line
done < "$1"

এবং

#!/usr/bin/env zsh
while read line; do
    echo $line
done < "$1"

এখন, তাদের আউটপুট তুলনা করুন:

$ bash.sh input 
foo bar baz
foo bar baz
$ zsh.sh input 
foo    bar    baz
foo    bar    baz

আপনি দেখতে পাচ্ছেন, যেহেতু আপনি উদ্ধৃতি দিচ্ছেন না $line, ট্যাবগুলি ব্যাশ দ্বারা সঠিকভাবে ব্যাখ্যা করা যায় না। Zsh এর সাথে আরও ভাল আচরণ করে বলে মনে হচ্ছে। এখন, ডিফল্টরূপে ফিল্ড ডিলিমিটার হিসাবে cutব্যবহার \tকরে। সুতরাং, যেহেতু আপনার bashস্ক্রিপ্টটি ট্যাবগুলি খাচ্ছে (বিভক্ত + গ্লোব অপারেটরের কারণে), cutকেবলমাত্র একটি ক্ষেত্র দেখে এবং সে অনুযায়ী কাজ করে। আপনি যা চালিয়ে যাচ্ছেন তা হ'ল:

$ echo "foo bar baz" | cut -f 2
foo bar baz

সুতরাং, উভয় শেলের মধ্যে আপনার স্ক্রিপ্টটি প্রত্যাশার মতো কাজ করতে আপনার ভেরিয়েবলটি উদ্ধৃত করুন:

while read line; do
    <<<"$line" cut -f 2
done < "$1"

তারপরে, উভয়ই একই আউটপুট উত্পাদন করে:

$ bash.sh input 
bar
bar
$ zsh.sh input 
bar
bar

দুর্দান্ত উত্তর! ধন্যবাদ (+1) আমি সর্বনিম্ন rep'ed প্রশ্নকর্তাকে যদিও গ্রহণ করব, যেহেতু তারা আমার মূর্খতা প্রকাশের জন্য যথাযথভাবে প্রশ্নের উত্তর দিয়েছিল।
স্পারহাক

actually সঠিকভাবে অন্তর্ভুক্ত করার জন্য একমাত্র উত্তর হিসাবে এখনও (এখনও এখনও) ভোট দিনbash.sh
লুয়ার

1

ইতিমধ্যে উত্তর হিসাবে দেওয়া হয়েছে, একটি ভেরিয়েবল ব্যবহার করার জন্য আরও বহনযোগ্য উপায় হ'ল উদ্ধৃতি:

$ printf '%s\t%s\t%s\n' foo bar baz
foo    bar    baz
$ l="$(printf '%s\t%s\t%s\n' foo bar baz)"
$ <<<$l     sed -n l
foo bar baz$

$ <<<"$l"   sed -n l
foo\tbar\tbaz$

রেখার সাথে ব্যাশে প্রয়োগের পার্থক্য রয়েছে:

l="$(printf '%s\t%s\t%s\n' foo bar baz)"; <<<$l  sed -n l

এটি বেশিরভাগ শেলের ফলাফল:

/bin/sh         : foo bar baz$
/bin/b43sh      : foo bar baz$
/bin/bash       : foo bar baz$
/bin/b44sh      : foo\tbar\tbaz$
/bin/y2sh       : foo\tbar\tbaz$
/bin/ksh        : foo\tbar\tbaz$
/bin/ksh93      : foo\tbar\tbaz$
/bin/lksh       : foo\tbar\tbaz$
/bin/mksh       : foo\tbar\tbaz$
/bin/mksh-static: foo\tbar\tbaz$
/usr/bin/ksh    : foo\tbar\tbaz$
/bin/zsh        : foo\tbar\tbaz$
/bin/zsh4       : foo\tbar\tbaz$

<<<যখন অনাবৃত হয় তখন কেবল ডানদিকে ভ্যাশিয়ালটি বিভক্ত করুন ।
যাইহোক, এটি বাশ সংস্করণে সংশোধন করা হয়েছে ৪.৪
এর অর্থ হল এর ফলাফলটির $IFSফলাফলকে প্রভাবিত করে <<<


লাইন সহ:

l=(1 2 3); IFS=:; sed -n l <<<"${l[*]}"

সমস্ত শেল মানগুলিতে যোগদানের জন্য আইএফএসের প্রথম অক্ষর ব্যবহার করে।

/bin/y2sh       : 1:2:3$
/bin/sh         : 1:2:3$
/bin/b43sh      : 1:2:3$
/bin/b44sh      : 1:2:3$
/bin/bash       : 1:2:3$
/bin/ksh        : 1:2:3$
/bin/ksh93      : 1:2:3$
/bin/lksh       : 1:2:3$
/bin/mksh       : 1:2:3$
/bin/zsh        : 1:2:3$
/bin/zsh4       : 1:2:3$

এর সাথে "${l[@]}", বিভিন্ন যুক্তি পৃথক করার জন্য একটি স্থান প্রয়োজন, তবে কিছু শাঁস আইএফএস থেকে মানটি ব্যবহার করতে পছন্দ করে (এটি কি সঠিক?)

/bin/y2sh       : 1:2:3$
/bin/sh         : 1 2 3$
/bin/b43sh      : 1 2 3$
/bin/b44sh      : 1 2 3$
/bin/bash       : 1 2 3$
/bin/ksh        : 1 2 3$
/bin/ksh93      : 1 2 3$
/bin/lksh       : 1:2:3$
/bin/mksh       : 1:2:3$
/bin/zsh        : 1:2:3$
/bin/zsh4       : 1:2:3$

নাল আইএফএসের সাহায্যে মানগুলি এই লাইনের সাথে যুক্ত হওয়া উচিত:

a=(1 2 3); IFS=''; sed -n l <<<"${a[*]}"

/bin/y2sh       : 123$
/bin/sh         : 123$
/bin/b43sh      : 123$
/bin/b44sh      : 123$
/bin/bash       : 123$
/bin/ksh        : 123$
/bin/ksh93      : 123$
/bin/lksh       : 1 2 3$
/bin/mksh       : 1 2 3$
/bin/zsh        : 123$
/bin/zsh4       : 123$

তবে লক্ষ এবং মীক উভয়ই এটি করতে ব্যর্থ।

আমরা যদি যুক্তিগুলির তালিকায় পরিবর্তন করি:

l=(1 2 3); IFS=''; sed -n l <<<"${l[@]}"

/bin/y2sh       : 123$
/bin/sh         : 1 2 3$
/bin/b43sh      : 1 2 3$
/bin/b44sh      : 1 2 3$
/bin/bash       : 1 2 3$
/bin/ksh        : 1 2 3$
/bin/ksh93      : 1 2 3$
/bin/lksh       : 1 2 3$
/bin/mksh       : 1 2 3$
/bin/zsh        : 123$
/bin/zsh4       : 123$

যশ এবং জেডএস উভয়ই যুক্তি আলাদা রাখতে ব্যর্থ। এটা কি বাগ?


প্রায়শই zsh/ yashএবং "${l[@]}"তালিকাভুক্ত নয় এমন প্রসঙ্গে, এটি নকশার ভিত্তিতে যেখানে "${l[@]}"কেবলমাত্র তালিকা প্রসঙ্গে বিশেষ। তালিকাভুক্ত নয় এমন প্রসঙ্গে, কোনও বিচ্ছেদ সম্ভব নয়, আপনাকে কোনওভাবে উপাদানগুলিতে যোগ দিতে হবে। Space আইএফএসের প্রথম চরিত্রের সাথে যোগদান করা কোনও স্পেস অক্ষর আইএমওর সাথে যোগ দেওয়ার চেয়ে আরও সামঞ্জস্যপূর্ণ। dashএটি পাশাপাশি করে ( dash -c 'IFS=; a=$@; echo "$a"' x a b)। পসিক্স যদিও আইআইআরসি পরিবর্তন করতে চাইছে। দেখুন এই (দীর্ঘ) আলোচনা
Stéphane Chazelas


আমার জবাব, না, দ্বিতীয় চেহারা পেয়ে, পসিক্স var=$@অনির্ধারিত আচরণটি ছেড়ে দেবে ।
স্টাফেন চেজেলাস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.