আমি কীভাবে কোনও কমান্ডের মধ্যে একটি ফাইল ব্যবহার করতে পারি এবং আউটপুটটিকে ছাঁটাই না করে পুনরায় ডাইরেক্ট করতে পারি?


98

মূলত আমি কোনও ফাইল থেকে ইনপুট পাঠ্য হিসাবে নিতে চাইছি, সেই ফাইলটি থেকে একটি লাইন সরিয়ে ফেলব এবং আউটপুটটিকে একই ফাইলটিতে পাঠাতে চাই। এই লাইন বরাবর কিছু যদি এটি আরও পরিষ্কার করে তোলে।

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > file_name

তবে, যখন আমি এটি করি আমি ফাঁকা ফাইল দিয়ে শেষ করি end কোন চিন্তা?


উত্তর:


85

আপনি এটি করতে পারবেন না কারণ বাশ প্রথমে পুনর্নির্দেশগুলি প্রক্রিয়া করে, তারপরে কমান্ডটি কার্যকর করে। সুতরাং গ্রেপ ফাইল_নামের দিকে তাকানোর সময়টি এটি ইতিমধ্যে খালি। আপনি যদিও একটি অস্থায়ী ফাইল ব্যবহার করতে পারেন।

#!/bin/sh
tmpfile=$(mktemp)
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > ${tmpfile}
cat ${tmpfile} > file_name
rm -f ${tmpfile}

এর মতো, tmpfilemktemp তৈরি করতে ব্যবহার করার কথা বিবেচনা করুন তবে নোট করুন যে এটি পসিক্স নয়।


47
আপনি এটি করতে না পারার কারণ: বাশ প্রথমে পুনর্নির্দেশগুলি প্রক্রিয়া করে, তারপরে কমান্ডটি কার্যকর করে। সুতরাং গ্রেপ ফাইল_নামের দিকে তাকানোর সময়টি এটি ইতিমধ্যে খালি।
গ্লেন জ্যাকম্যান

4
@glennjackman: "পুনর্নির্দেশ প্রক্রিয়া দ্বারা আপনি বোঝাচ্ছেন যে>> এর ক্ষেত্রে এটি ফাইলটি খোলে এবং এটি পরিষ্কার করে দেয় এবং >> এর ক্ষেত্রে এটি কেবল এটি খুলবে"?
রাজওয়ান

4
হ্যাঁ, তবে এই পরিস্থিতিতে লক্ষণীয়, >পুনর্নির্দেশটি ফাইলটি খুলবে এবং শেলটি আরম্ভ হওয়ার আগে এটি কেটে যাবে grep
গ্লেন জ্যাকম্যান

4
আপনি যদি কোনও অস্থায়ী ফাইল ব্যবহার করতে না চান তবে আমার উত্তর দেখুন , তবে দয়া করে এই মন্তব্যটিকে উজ্জীবিত করবেন না।
জ্যাক মরিস

এর পরিবর্তে, আদেশটি ব্যবহার করে উত্তরটিsponge গ্রহণ করা উচিত।
vlz

98

এই ধরণের কাজের জন্য স্পঞ্জ ব্যবহার করুন । মোরটিলসের এটির অংশ।

এই আদেশটি ব্যবহার করে দেখুন:

 grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | sponge file_name

4
উত্তর করার জন্য ধন্যবাদ. সম্ভবত সহায়ক সংযোজন হিসাবে, আপনি যদি ম্যাকের হোমব্রু ব্যবহার করছেন তবে এটি ব্যবহার করতে পারেন brew install moreutils
অ্যান্টনি পানোজো

4
অথবা sudo apt-get install moreutilsডেবিয়ান-ভিত্তিক সিস্টেমগুলিতে।
জোনা

4
ধিক! আমাকে সেখানে আরও কিছু ভাল প্রোগ্রামের সাথে পরিচয় করিয়ে দেওয়ার জন্য ধন্যবাদ)!
নেটিগার

আপনাকে অনেক ধন্যবাদ, উদ্ধার জন্য আরও কিছু! বসের মতো স্পঞ্জ!
অ্যাকোয়াড্রো

4
সাবধানতার কথা, "স্পঞ্জ" ধ্বংসাত্মক, সুতরাং আপনার কমান্ডে যদি কোনও ত্রুটি থাকে তবে আপনি নিজের ইনপুট ফাইলটি মুছতে পারেন (যেমন আমি প্রথমবার স্পঞ্জ চেষ্টা করেছিলাম)। আপনার কমান্ডটি কাজ করছে কিনা তা নিশ্চিত করুন, এবং / অথবা ইনপুট ফাইলটি আপনি কমান্ডটি কাজ করার বিষয়ে পুনরাবৃত্তি করতে চাইলে সংস্করণ নিয়ন্ত্রণে রয়েছে।
ব্যবহারকারী 107172

19

পরিবর্তে সেড ব্যবহার করুন:

sed -i '/seg[0-9]\{1,\}\.[0-9]\{1\}/d' file_name

4
আইরিক -iকেবল জিএনইউ এক্সটেনশন, কেবল লক্ষণীয় just
c00kiemon5ter

4
* বিএসডি তে (এবং এটিও ওএসএক্স) আপনি বলতে -i ''পারেন তাই বর্ধন কঠোরভাবে বাধ্যতামূলক নয়, তবে -iবিকল্পটির জন্য কিছু যুক্তি প্রয়োজন ।
ট্রিপলি

16

এই সহজ চেষ্টা করুন

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | tee file_name

আপনার ফাইলটি এবার ফাঁকা হবে না :) এবং আপনার আউটপুটটিও আপনার টার্মিনালে মুদ্রিত হবে।


4
আমি এই সমাধান পছন্দ! এবং আপনি যদি এটি টার্মিনালে মুদ্রিত না করতে চান তবে আপনি এখনও আউটপুটটিকে /dev/nullঅনুরূপ জায়গায় পুনর্নির্দেশ করতে পারেন ।
হিমায়িত

4
এটি এখানে ফাইলের সামগ্রীগুলিও সাফ করে। এটি কি কোনও জিএনইউ / বিএসডি পার্থক্যের কারণে? আমি ম্যাকোজে আছি ...
এসএসসি

7

আপনি একই ফাইলটিতে পুনঃনির্দেশ অপারেটর ( >বা >>) ব্যবহার করতে পারবেন না , কারণ এটির উচ্চতরত্ব রয়েছে এবং এটি কমান্ডটি চালিত হওয়ার আগেই ফাইলটি তৈরি / কাটাবে। এটি এড়াতে আপনার যথাযথ সরঞ্জামগুলি ব্যবহার করা উচিত tee, যেমন sponge, sed -iবা অন্য কোনও সরঞ্জাম যা ফাইলে ফলাফল লিখতে পারে (যেমন sort file -o file))

মূলত একই মূল ফাইলে ইনপুটটি পুনর্নির্দেশ করা কোনও অর্থবোধ করে না এবং এর জন্য আপনার যথাস্থানে যথাযথ সম্পাদকগুলি ব্যবহার করা উচিত, উদাহরণস্বরূপ প্রাক্তন সম্পাদক (ভিমের অংশ):

ex '+g/seg[0-9]\{1,\}\.[0-9]\{1\}/d' -scwq file_name

কোথায়:

  • '+cmd'/ -c- যে কোনও প্রাক্তন / ভিএম কমান্ড চালান
  • g/pattern/d- গ্লোবাল ( help :g) ব্যবহার করে কোনও প্যাটার্নের সাথে মিলিত লাইনগুলি সরান
  • -s- নীরব মোড ( man ex)
  • -c wq- কার্যকর :writeএবং :quitআদেশ

আপনি এই ব্যবহার করতে sed, একই অর্জনে (ইতিমধ্যে অন্যান্য উত্তর দেখানো হিসাবে) তবে ইন-জায়গা ( -i) (ইউনিক্স / লিনাক্স মধ্যে ভিন্নভাবে কাজ করতে পারে) অ-মানক FreeBSD 'র এক্সটেনশান এবং মূলত এটি একটি এর গুলি tream ইডি itor, না একটি ফাইল সম্পাদক । দেখুন: প্রাক্তন মোডের কোনও ব্যবহারিক ব্যবহার আছে?


6

একটি লাইনারের বিকল্প - ফাইলের সামগ্রীটি পরিবর্তনশীল হিসাবে সেট করুন:

VAR=`cat file_name`; echo "$VAR"|grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' > file_name

4

যেহেতু এই প্রশ্নটি অনুসন্ধান ইঞ্জিনগুলির শীর্ষ ফলাফল, এখানে https://serverfault.com/a/547331 এর উপর ভিত্তি করে একটি ওয়ান-লাইনার রয়েছে spongeযা পরিবর্তে একটি সাব-শেল ব্যবহার করে (যা প্রায়শই ওএস এক্সের মতো ভ্যানিলা ইনস্টলের অংশ হয় না) :

echo "$(grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name)" > file_name

সাধারণ কেসটি হ'ল:

echo "$(cat file_name)" > file_name

সম্পাদনা করুন, উপরের সমাধানটিতে কিছু সতর্কতা রয়েছে:

  • printf '%s' <string>পরিবর্তে echo <string>এমনটি ব্যবহার করা উচিত যাতে এতে থাকা ফাইলগুলি -nঅনাকাঙ্ক্ষিত আচরণের কারণ না ঘটে ।
  • কমান্ড প্রতিকল্পন রেখাচিত্রমালা নতুন লাইন trailing ( এই ব্যাশ মত শাঁস একটি বাগ / বৈশিষ্ট্য ) তাই আমরা মত একটি পোস্টসাফিক্স চরিত্র সংযোজন করা উচিত xআউটপুট এবং মাধ্যমে বাইরে এটি অপসারণ একটি অস্থায়ী ভেরিয়েবলের প্যারামিটার সম্প্রসারণ মত ${v%x}
  • একটি অস্থায়ী পরিবর্তনশীল ব্যবহার করে বর্তমান শেল পরিবেশে যে $vকোনও বিদ্যমান ভেরিয়েবলের মান স্টম্পস করে $v, তাই পূর্ববর্তী মানটি সংরক্ষণ করার জন্য আমাদের সমগ্র অভিব্যক্তিটিকে বন্ধনীতে বাসাতে হবে।
  • বাশের মতো শেলের আরও একটি বাগ / বৈশিষ্ট্য হ'ল কমান্ড প্রতিস্থাপনটি nullআউটপুট থেকে অরক্ষিত অক্ষরগুলি সরিয়ে দেয়। আমি dd if=/dev/zero bs=1 count=1 >> file_nameএটি কল করে এবং এটিকে হেক্স সহ দেখে যাচাই করেছি cat file_name | xxd -p। তবে echo $(cat file_name) | xxd -pছিনতাই হয়। তাই এই উত্তর দিতে হবে না , বাইনারি ফাইল বা অমুদ্রণীয় অক্ষর ব্যবহার করে কিছু ব্যবহার করা যেমন লিঞ্চ নির্দিষ্ট

সাধারণ সমাধান (অ্যালবাইট কিছুটা ধীরে ধীরে, আরও মেমরি নিবিড় এবং এখনও ছাপানো অক্ষর ছাড়াই):

(v=$(cat file_name; printf x); printf '%s' ${v%x} > file_name)

Https://askubuntu.com/a/752451 থেকে পরীক্ষা :

printf "hello\nworld\n" > file_uniquely_named.txt && for ((i=0; i<1000; i++)); do (v=$(cat file_uniquely_named.txt; printf x); printf '%s' ${v%x} > file_uniquely_named.txt); done; cat file_uniquely_named.txt; rm file_uniquely_named.txt

মুদ্রণ করা উচিত:

hello
world

যদিও cat file_uniquely_named.txt > file_uniquely_named.txtবর্তমান শেলটিতে কল করা :

printf "hello\nworld\n" > file_uniquely_named.txt && for ((i=0; i<1000; i++)); do cat file_uniquely_named.txt > file_uniquely_named.txt; done; cat file_uniquely_named.txt; rm file_uniquely_named.txt

একটি খালি স্ট্রিং মুদ্রণ করে।

আমি বড় ফাইলগুলিতে এটি পরীক্ষা করিনি (সম্ভবত 2 বা 4 গিগাবাইটের বেশি)।

এই উত্তরটি আমি হার্ট সিমহা এবং কোস-এর কাছ থেকে নিয়েছি ।


4
অবশ্যই এটি বড় ফাইলের সাথে কাজ করবে না। এটি সম্ভবত একটি ভাল সমাধান বা পুরো সময় কাজ করতে পারে না। যা হচ্ছে তা হ'ল বাশ প্রথমে কমান্ডটি কার্যকর করে এবং তারপরে stdout লোড করে catএটিকে প্রথম আর্গুমেন্ট হিসাবে রাখে echo। অবশ্যই নন প্রিন্টেবল ভেরিয়েবলগুলি সঠিকভাবে আউটপুট এবং ডেটাটিকে দূষিত করবে না। নিজেই কোনও ফাইল পুনর্নির্দেশের চেষ্টা করবেন না, এটি ভাল হতে পারে না।
লিচ

1

এছাড়াও রয়েছে ed(বিকল্প হিসাবে sed -i):

# cf. http://wiki.bash-hackers.org/howto/edit-ed
printf '%s\n' H 'g/seg[0-9]\{1,\}\.[0-9]\{1\}/d' wq |  ed -s file_name

1

প্রক্রিয়া-বিকল্প ব্যবহার করে আপনি এটি করতে পারেন ।

এটি হ্যাকের কিছুটা হলেও যদিও বাশ সমস্ত পাইপগুলিকে অবিচ্ছিন্নভাবে খোলে এবং sleepতাই ওয়াইএমএমভি ব্যবহার করে আমাদের এটি ঘিরে কাজ করতে হবে ।

আপনার উদাহরণে:

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > >(sleep 1 && cat > file_name)
  • >(sleep 1 && cat > file_name) একটি অস্থায়ী ফাইল তৈরি করে যা গ্রেপ থেকে আউটপুট গ্রহণ করে
  • sleep 1 ইনপুট ফাইলটি বিশ্লেষণের জন্য গ্রেপ সময় দেওয়ার জন্য এক সেকেন্ডের জন্য বিলম্ব
  • অবশেষে cat > file_nameআউটপুট লিখুন

1

আপনি পসিএক্স আওক দিয়ে স্লুর্প ব্যবহার করতে পারেন:

!/seg[0-9]\{1,\}\.[0-9]\{1\}/ {
  q = q ? q RS $0 : $0
}
END {
  print q > ARGV[1]
}

উদাহরণ


4
এটি সম্ভবত নির্দেশ করা উচিত যে "স্লুর্প" এর অর্থ "পুরো ফাইলটি মেমরিতে পড়ুন"। আপনার কাছে যদি একটি বড় ইনপুট ফাইল থাকে, তবে আপনি এটি এড়াতে চান।
ট্রিপলি

1

এটি খুব সম্ভব, আপনাকে কেবল এটি নিশ্চিত করতে হবে যে আপনি আউটপুটটি লেখার সময় আপনি এটি অন্য কোনও ফাইলে লিখছেন। এটি ফাইলের বিবরণী ফাইল খোলার পরে ফাইলটি মুছে ফেলার মাধ্যমে করা যেতে পারে তবে এটি লেখার আগে:

exec 3<file ; rm file; COMMAND <&3 >file ;  exec 3>&-

বা এটি আরও ভালভাবে বুঝতে, লাইনে লাইন করুন:

exec 3<file       # open a file descriptor reading 'file'
rm file           # remove file (but fd3 will still point to the removed file)
COMMAND <&3 >file # run command, with the removed file as input
exec 3>&-         # close the file descriptor

এটি করা এখনও ঝুঁকিপূর্ণ কাজ, কারণ যদি কম্যান্ড সঠিকভাবে চালাতে ব্যর্থ হয় তবে আপনি ফাইলের বিষয়বস্তু হারাবেন। যদি কম্ম্যান্ড একটি শূন্য-বহির্গমন কোড ফেরত দেয় তবে ফাইলটি পুনরুদ্ধার করে এটিকে প্রশমিত করা যায়:

exec 3<file ; rm file; COMMAND <&3 >file || cat <&3 >file ; exec 3>&-

এটি ব্যবহার করা আরও সহজ করার জন্য আমরা শেল ফাংশনটিও সংজ্ঞায়িত করতে পারি:

# Usage: replace FILE COMMAND
replace() { exec 3<$1 ; rm $1; ${@:2} <&3 >$1 || cat <&3 >$1 ; exec 3>&- }

উদাহরণ:

$ echo aaa > test
$ replace test tr a b
$ cat test
bbb

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


0

এটা চেষ্টা কর

echo -e "AAA\nBBB\nCCC" > testfile

cat testfile
AAA
BBB
CCC

echo "$(grep -v 'AAA' testfile)" > testfile
cat testfile
BBB
CCC

একটি সংক্ষিপ্ত ব্যাখ্যা বা এমনকি মন্তব্য সহায়ক হতে পারে।
ধনী

আমি মনে করি, এটি কাজ করে কারণ স্ট্রিং এক্সট্রোপোলেশন অপারেটর পুনর্নির্দেশের আগে
সম্পাদন করে

0

নিম্নলিখিত spongeপ্রয়োজন ছাড়াই একই কাজ সম্পাদন করবে moreutils:

    shuf --output=file --random-source=/dev/zero 

--random-source=/dev/zeroঅংশ ঠাট shufএকেবারেই কোনও প্রকাশের shuffling না করে তার জিনিস করছেন মধ্যে, তাই এটি এটা পরিবর্তন ছাড়া আপনার ইনপুট বাফার হবে।

যাইহোক, এটি সত্য যে অস্থায়ী ফাইল ব্যবহার করা সর্বোত্তম, কার্যকারিতার কারণে। সুতরাং, আমি এখানে একটি ফাংশন লিখেছি যা এটি আপনার জন্য একটি সাধারণীকরণের উপায়ে করবে:

# Pipes a file into a command, and pipes the output of that command
# back into the same file, ensuring that the file is not truncated.
# Parameters:
#    $1: the file.
#    $2: the command. (With $3... being its arguments.)
# See https://stackoverflow.com/a/55655338/773113

function siphon
{
    local tmp=$(mktemp)
    local file="$1"
    shift
    $* < "$file" > "$tmp"
    mv "$tmp" "$file"
}

-2

আমি সাধারণত এটি করতে টি প্রোগ্রাম ব্যবহার করি:

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | tee file_name

এটি নিজেই একটি টেম্পাইল তৈরি করে এবং অপসারণ করে।


দুঃখিত, teeকাজের নিশ্চয়তা নেই। Askubuntu.com/a/752451/335781 দেখুন ।
স্টাডিজিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.