আমি কীভাবে ব্যাশে ট্রেলিং করা নতুন লাইনটি মুছতে পারি?


10

আমি এমন কিছু খুঁজছি যা পার্লের মতো আচরণ করে chomp। আমি একটি কমান্ড খুঁজছি যা কেবলমাত্র তার ইনপুট প্রিন্ট করে, সর্বশেষ অক্ষরটি যদি এটি একটি নতুন লাইন থাকে তবে:

$ printf "one\ntwo\n" | COMMAND_IM_LOOKING_FOR ; echo " done"
one
two done
$ printf "one\ntwo" | COMMAND_IM_LOOKING_FOR ; echo " done"
one
two done

(বাশ এবং জেড-এর কমান্ড প্রতিস্থাপনটি সমস্ত চলমান নতুন লাইন মুছে ফেলে, তবে আমি এমন কিছু সন্ধান করছি যা একটি নতুন ট্র্যাকিংয়ের নতুন লাইন মুছে দেয়))

উত্তর:


9

এই কাজ করা উচিত:

printf "one\ntwo\n" | awk 'NR>1{print PREV} {PREV=$0} END{printf("%s",$0)}' ; echo " done"

স্ক্রিপ্ট সর্বদা বর্তমানের পরিবর্তে পূর্ববর্তী লাইনটি প্রিন্ট করে এবং শেষ লাইনের সাথে আলাদাভাবে আচরণ করা হয়।

এটি আরও বিশদে কী করে:

  1. NR>1{print PREV} পূর্ববর্তী লাইনটি মুদ্রণ করুন (প্রথমবার বাদে)।
  2. {PREV=$0}PREVপরিবর্তনশীল বর্তমান লাইন সঞ্চয় ।
  3. END{printf("%s",$0)} অবশেষে, শেষ লাইনটি আউটআউট লাইন ব্রেকটি মুদ্রণ করুন।

এছাড়াও নোট করুন এটি সর্বশেষে একটি খালি লাইন সরিয়ে ফেলবে (অপসারণের জন্য কোনও সমর্থন নেই "one\ntwo\n\n\n")।


15

আপনি perlছাড়া ব্যবহার করতে পারেন chomp:

$ printf "one\ntwo\n" | perl -0 -pe 's/\n\Z//'; echo " done"
one
two done

$ printf "one\ntwo" | perl -0 -pe 's/\n\Z//'; echo " done"
one
two done

তবে কেন chompনিজেকে ব্যবহার করবেন না :

$ printf "one\ntwo\n" | perl -pe 'chomp if eof'; echo " done"

4

আপনি যদি এর সঠিক সমতুল্য চান chompতবে আমার মনের কাছে প্রথম যে পদ্ধতিটি আসে তা হ'ল ল্যাটিনসুড ইতিমধ্যে পোস্ট করা বিশুদ্ধ সমাধান । আমি কিছু অন্যান্য পদ্ধতি যুক্ত করব যা প্রায়শই ব্যবহৃত হয় chompএমন কিছু সাধারণ কাজ বাস্তবায়ন করে না তবে বাস্তবায়িত করে chomp

আপনি যখন কোনও পাঠ্যকে একটি ভেরিয়েবলে স্টাফ করেন, শেষে সমস্ত নিউলাইনগুলি ছিনিয়ে নেওয়া হয়। সুতরাং এই সমস্ত কমান্ড একই একক লাইন আউটপুট উত্পাদন করে:

echo "$(printf 'one\ntwo') done"
echo "$(printf 'one\ntwo\n') done"
echo "$(printf 'one\ntwo\n\n') done"
echo "$(printf 'one\ntwo\n\n\n\n\n\n\n\n\n\n') done"

আপনি যদি কোনও ফাইলের শেষ পংক্তিতে বা কমান্ডের আউটপুটটিতে কিছু পাঠ্য যুক্ত করতে চান sedতবে সুবিধাজনক হতে পারে। জিএনইউ সেড এবং বেশিরভাগ আধুনিক বাস্তবায়ন সহ, ইনপুটটি কোনও নতুন লাইনে শেষ না হলেও- এটি কাজ করে; তবে ইতিমধ্যে যদি এটি না থাকে তবে এটি কোনও নতুন লাইন যুক্ত করবে না।

sed '$ s/$/ done/'

¹ তবে এটি সমস্ত সেড বাস্তবায়নের সাথে কাজ করে না: সেড একটি পাঠ্য প্রক্রিয়াকরণ সরঞ্জাম এবং একটি ফাইল যা খালি নয় এবং একটি নিউলাইন চরিত্রের সাথে শেষ হয় না এটি কোনও পাঠ্য ফাইল নয়।


এটি হুবহু সমতুল্য নয় chomp, কারণ chompকেবলমাত্র একটির পিছনে থাকা নতুন লাইনটি মুছে ফেলা হয়।
Flimm

@ ফ্লিম হ্যাঁ, এর সবচেয়ে সুস্পষ্ট সঠিক সমতুল্য chompহ'ল ল্যাটিনসুড ইতিমধ্যে পোস্ট করা অজানা সমাধান solution তবে অনেক ক্ষেত্রে chompএকটি কাজ করার কেবল একটি সরঞ্জাম এবং আমি কিছু সাধারণ কাজ করার উপায় সরবরাহ করি। এটি পরিষ্কার করতে আমার উত্তর আপডেট করুন Let
গিলস 'অশুচি হওয়া বন্ধ করুন'

1

অন্য perlপদ্ধতির। এটি পুরোপুরি মেমোরিতে পড়বে তাই এটি প্রচুর পরিমাণে ডেটা (কুওনলমের ব্যবহার বা তার awkজন্য পদ্ধতির ব্যবহারের জন্য) ভাল ধারণা হতে পারে না :

$ printf "one\ntwo\n" | perl -0777pe 's/\n$//'; echo " done"
one
two done

ধন্যবাদ, @ স্টাফেনচেজেলাস, স্থির। কোনও কারণে, এই সুইচটি আমাকে সর্বদা বিভ্রান্ত করে !
টেরডন

0

আমি এটি কোথাও একটি গিথুব রেপো থেকে ছিনিয়ে নিয়েছি, কিন্তু কোথায় পাই না

মুছতে-trailing-ফাঁকা-লাইন-sed

#!/bin/bash
#
# Delete all trailing blank lines.
# From http://sed.sourceforge.net/sed1line.txt
#
# Version: 1.3.0
# Created: 2011-01-02
# Updated: 2015-01-25
# Contact: Joel Parker Henderson (joel@joelparkerhenderson.com)
# License: GPL
##
set -euf
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'

0

বিমূর্ত

নিউলাইন ছাড়াই লাইনগুলি মুদ্রণ করুন, মুদ্রণের জন্য অন্য লাইন থাকলে কেবল একটি নতুন লাইন যুক্ত করুন।

$ printf 'one\ntwo\n' | 

     awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }';   echo " done"

one
two done

অন্যান্য সমাধান

যদি আমরা কোনও ফাইল নিয়ে কাজ করি তবে আমরা কেবলমাত্র এটি থেকে একটি অক্ষর ছিন্ন করতে পারি (যদি এটি একটি নতুন লাইনে শেষ হয়):

মুছে ফেলা ট্রেলইনলাইন () {[[$ (লেজ -c 1 "$ 1")]] || কাটা কাটা -s-1 "$ 1"; }

এটি একটি দ্রুত সমাধান কারণ এটি ফাইল থেকে কেবল একটি অক্ষর পড়তে হবে এবং তারপরে truncateপুরো ফাইলটি না পড়ে সরাসরি ( ) সরিয়ে ফেলতে হবে ।

তবে, স্টিডিন (একটি স্ট্রিম) থেকে ডেটা নিয়ে কাজ করার সময় অবশ্যই এটি পড়তে হবে। এবং এটি পড়ার সাথে সাথে এটি "গ্রাস" হয়ে যায়। ব্যাকট্র্যাক নেই (ট্র্যাঙ্কেটের মতো)। একটি স্ট্রিমের শেষ সন্ধানের জন্য আমাদের স্রোতের শেষ প্রান্তে পড়তে হবে। সেই সময়ে, ইনপুট স্ট্রিমে ফিরে যাওয়ার কোনও উপায় নেই, ডেটা ইতিমধ্যে "গ্রাস" হয়ে গেছে " এর অর্থ হ'ল আমরা স্ট্রিমের শেষের সাথে মেলে না যাওয়া এবং তারপরে বাফারের সাথে ডেটা দিয়ে কিছু না করা পর্যন্ত ডেটা অবশ্যই কোনও না কোনও আকারে বাফারে সংরক্ষণ করতে হবে।

সমাধানগুলির মধ্যে সর্বাধিক সুস্পষ্ট হ'ল স্ট্রিমটিকে একটি ফাইলে রূপান্তর করা এবং সেই ফাইলটি প্রক্রিয়া করা। তবে প্রশ্নটি স্ট্রিমের এক ধরণের ফিল্টার চায়। অতিরিক্ত ফাইল ব্যবহার সম্পর্কে নয়।

পরিবর্তনশীল

নিষ্পাপ সমাধানটি হ'ল পুরো ইনপুটটি একটি ভেরিয়েবলের মধ্যে ক্যাপচার করা:

FilterOne(){ filecontents=$(cat; echo "x");        # capture the whole input
             filecontents=${filecontents%x};       # Remove the "x" added above.
             nl=$'\n';                             # use a variable for newline.
             printf '%s' "${filecontents%"$nl"}";  # Remove newline (if it exists).
       }

printf 'one\ntwo'     | FilterOne ; echo 1done
printf 'one\ntwo\n'   | FilterOne ; echo 2done
printf 'one\ntwo\n\n' | FilterOne ; echo 3done

স্মৃতি

সেড দিয়ে মেমরিতে একটি সম্পূর্ণ ফাইল লোড করা সম্ভব। সিডে শেষ লাইনে ট্রেলিং করা নতুন লাইন এড়ানো অসম্ভব। জিএনইউ শেড একটি নতুন ট্র্যাকিং নতুন লাইনের মুদ্রণ এড়াতে পারে তবে কেবল যদি উত্স ফাইলটি এটি অনুপস্থিত থাকে। সুতরাং, না, সরল সেড সাহায্য করতে পারে না।

-zবিকল্পটি সহ জিএনইউ অ্যাডকে বাদ দিয়ে :

sed -z 's/\(.*\)\n$/\1/'

Awk (যে কোনও awk) এর সাহায্যে পুরো স্ট্রিম স্লার্প করুন এবং printfএটি নতুন লাইনের পিছনে ছাড়াই।

awk '    { content = content $0 RS } 
     END { gsub( "\n$", "", content ); printf( "%s", content ) }
    '

পুরো ফাইলটিকে মেমোরিতে লোড করা ভাল ধারণা নাও হতে পারে, এটি প্রচুর স্মৃতিতে গ্রাস করতে পারে।

স্মৃতিতে দুটি লাইন

অজানাতে, আমরা ভেরিয়েবলের মধ্যে পূর্ববর্তী লাইনটি সঞ্চয় করে এবং বর্তমানের একটি মুদ্রণ করে লুপ প্রতি দুটি লাইন প্রক্রিয়া করতে পারি:

awk 'NR>1{print previous} {previous=$0} END {printf("%s",$0)}'

সরাসরি প্রক্রিয়াজাতকরণ

তবে আমরা আরও ভাল করতে পারে।

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

awk 'NR == 1 {printf ("% s", $ 0); পরের next; {প্রিন্টফ ("\ n% s", $ 0)} '

বা, অন্য কোনওভাবে লেখা:

awk 'NR>1{ print "" }; { printf( "%s", $0 ) }'

বা:

awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'

তাই:

$ printf 'one\ntwo\n' | awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'; echo " done"
one
two done
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.