كيف يمكنني تنفيذ أي أمر بتحرير ملفه (الوسيطة) "في مكانه" باستخدام bash؟
-
02-07-2019 - |
سؤال
لدي ملف temp.txt، وأريد فرزه باستخدام ملف sort
الأمر في باش.
أريد أن تحل النتائج التي تم فرزها محل الملف الأصلي.
هذا لا يعمل على سبيل المثال (أحصل على ملف فارغ):
sortx temp.txt > temp.txt
وهل يمكن عمل ذلك في سطر واحد دون اللجوء إلى النسخ إلى الملفات المؤقتة؟
يحرر:ال -o
الخيار رائع جدًا لـ sort
.إستعملت sort
في سؤالي كمثال.أواجه نفس المشكلة مع الأوامر الأخرى:
uniq temp.txt > temp.txt.
هل هناك حل عام أفضل؟
المحلول
sort temp.txt -o temp.txt
نصائح أخرى
أ sort
يحتاج إلى رؤية كل المدخلات قبل أن يتمكن من البدء في الإخراج.ولهذا السبب فإن sort
يمكن للبرنامج أن يقدم بسهولة خيارًا لتعديل ملف في مكانه:
sort temp.txt -o temp.txt
على وجه التحديد، توثيق جنو sort
يقول:
عادةً، يقرأ الفرز جميع المدخلات قبل فتح ملف الإخراج، بحيث يمكنك فرز الملف بأمان في مكانه باستخدام أوامر مثل
sort -o F F
وcat F | sort -o F
.لكن،sort
مع--merge
(-m
) يمكنه فتح ملف الإخراج قبل قراءة كل المدخلات، لذا فإن الأمر مثلcat F | sort -m -o F - G
ليست آمنة حيث قد يبدأ النوع في الكتابةF
قبلcat
تم الانتهاء من قراءته.
بينما توثيق BSD sort
يقول:
إذا كان ملف الإخراج هو أحد ملفات الإدخال، فقم بنسخه إلى ملف مؤقت قبل فرز وكتابة الإخراج إلى ملف الإخراج.
أوامر مثل uniq
يمكنهم البدء في كتابة المخرجات قبل الانتهاء من قراءة المدخلات.لا تدعم هذه الأوامر عادةً التحرير الموضعي (وسيكون من الصعب عليها دعم هذه الميزة).
يمكنك حل هذه المشكلة عادةً باستخدام ملف مؤقت، أو إذا كنت تريد تمامًا تجنب وجود ملف وسيط، فيمكنك استخدام مخزن مؤقت لتخزين النتيجة الكاملة قبل كتابتها.على سبيل المثال، مع perl
:
uniq temp.txt | perl -e 'undef $/; $_ = <>; open(OUT,">temp.txt"); print OUT;'
هنا، يقرأ جزء Perl الإخراج الكامل من uniq
ثابت $_
ثم يقوم بالكتابة فوق الملف الأصلي بهذه البيانات.يمكنك أن تفعل الشيء نفسه في لغة البرمجة النصية التي تختارها، وربما حتى في Bash.لكن لاحظ أنه سيحتاج إلى ذاكرة كافية لتخزين الملف بأكمله، وهذا غير مستحسن عند العمل مع الملفات الكبيرة.
فيما يلي نهج أكثر عمومية، يعمل مع UNIQ، وفرز، وما إلى ذلك.
{ rm file && uniq > file; } < file
تعليق توبو على الإسفنج يضمن أن يكون إجابة في حد ذاته.
على الاقتباس من com.moreutils الصفحة الرئيسية:
ربما تكون أداة الأغراض العامة الأكثر استخدامًا حتى الآن هي الإسفنجة (1)، والتي تتيح لك القيام بأشياء مثل هذه:
% sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd
لكن، sponge
يعاني من نفس المشكلة تعليقات ستيف جيسوب هنا. إذا كان أي من الأوامر في خط الأنابيب من قبل sponge
إذا فشلت، فسيتم كتابة الملف الأصلي.
$ mistyped_command my-important-file | sponge my-important-file
mistyped-command: command not found
اه أوه، my-important-file
ذهب.
تفضل، سطر واحد:
sort temp.txt > temp.txt.sort && mv temp.txt.sort temp.txt
من الناحية الفنية، لا يوجد نسخ إلى ملف مؤقت، ويجب أن يكون الأمر "mv" فوريًا.
انا احب ال sort file -o file
الإجابة ولكن لا تريد كتابة نفس اسم الملف مرتين.
باستخدام باش توسيع التاريخ:
$ sort file -o !#^
يمسك الوسيط الأول للسطر الحالي عند الضغط عليه يدخل.
نوع فريد في المكان:
$ sort -u -o file !#$
الاستيلاء على الوسيط الأخير في السطر الحالي.
وقد ذكر كثيرون -س خيار.هنا هو جزء صفحة الرجل.
من صفحة الرجل:
-o output-file
Write output to output-file instead of to the standard output.
If output-file is one of the input files, sort copies it to a
temporary file before sorting and writing the output to output-
file.
قد يكون هذا مقيدًا للغاية للذاكرة، ولكن يمكنك استخدام awk لتخزين البيانات المتوسطة في الذاكرة، ثم كتابتها مرة أخرى.
uniq temp.txt | awk '{line[i++] = $0}END{for(j=0;j<i;j++){print line[j]}}' > temp.txt
بديل ل sponge
مع أكثر شيوعا sed
:
sed -ni r<(command file) file
يعمل لأي أمر (sort
, uniq
, tac
, ، ...) ويستخدم المشهور جدًا sed
'س -i
خيار (تحرير الملفات في المكان).
تحذير: يحاول command file
أولاً لأن تحرير الملفات في مكانها ليس آمنًا بطبيعته.
توضيح
أولا، أنت تقول sed
عدم طباعة الأسطر (الأصلية) (-n
خيار)، وبمساعدة sed
'س r
يأمر و bash
'س استبدال العملية, ، المحتوى الذي تم إنشاؤه بواسطة <(command file)
سيتم حفظ الإخراج في المكان.
جعل الأمور أسهل
يمكنك لف هذا الحل في دالة:
ip_cmd() { # in place command
CMD=${1:?You must specify a command}
FILE=${2:?You must specify a file}
sed -ni r<("$CMD" "$FILE") "$FILE"
}
مثال
$ cat file
d
b
c
b
a
$ ip_cmd sort file
$ cat file
a
b
b
c
d
$ ip_cmd uniq file
$ cat file
a
b
c
d
$ ip_cmd tac file
$ cat file
d
c
b
a
$ ip_cmd
bash: 1: You must specify a command
$ ip_cmd uniq
bash: 2: You must specify a file
استخدم الحجة --output=
أو -o
لقد قمت للتو بالتجربة على FreeBSD:
sort temp.txt -otemp.txt
لإضافة uniq
القدرة، ما هي الجوانب السلبية ل:
sort inputfile | uniq | sort -o inputfile
اقرأ عن المحرر غير التفاعلي، ex
.
إذا كنت تصر على استخدام sort
في البرنامج، يجب عليك استخدام ملف وسيط - لا أعتقد ذلك sort
لديه خيار للفرز في الذاكرة.ستفشل أي خدعة أخرى باستخدام stdin/stdout ما لم تتمكن من ضمان أن حجم المخزن المؤقت لـ stdin الخاص بالفرز كبير بما يكفي ليناسب الملف بأكمله.
يحرر:عار علي. sort temp.txt -o temp.txt
يعمل بشكل ممتاز.
حل آخر:
uniq file 1<> file