كيف يمكنني استخراج نطاق محدد مسبقًا من الأسطر من ملف نصي على Unix؟
-
01-07-2019 - |
سؤال
لدي ملف SQL يحتوي على 23000 سطر تقريبًا يحتوي على العديد من قواعد البيانات ذات القيمة البيانات.أحتاج إلى استخراج قسم معين من هذا الملف (أي.البيانات لقاعدة بيانات واحدة) ووضعها في ملف جديد.أعرف أرقام سطر البداية والنهاية للبيانات التي أريدها.
هل يعرف أحد أمر Unix (أو سلسلة من الأوامر) لاستخراج جميع الأسطر من ملف بين السطر 16224 و16482 ثم إعادة توجيهها إلى ملف جديد؟
المحلول
sed -n '16224,16482p;16483q' filename > newfile
من دليل سيد:
ص - طباعة مساحة النمط (إلى الإخراج القياسي).عادةً ما يتم استخدام هذا الأمر فقط مع خيار سطر الأوامر -n.
ن - إذا لم يتم تعطيل الطباعة التلقائية ، فقم بطباعة مساحة الأنماط ، إذن ، بغض النظر ، استبدل مساحة النمط بالخط التالي من الإدخال.إذا لم يكن هناك المزيد من المدخلات ، فستخرج SED دون معالجة أي أوامر أخرى.
س - مخرج
sed
دون معالجة أي أوامر أو إدخالات أخرى.لاحظ أنه تتم طباعة مساحة النمط الحالية إذا لم يتم تعطيل الطباعة التلقائية باستخدام الخيار -n.
يمكن أن تكون العناوين الموجودة في البرنامج النصي sed بأي من الأشكال التالية:
رقمتحديد رقم السطر سوف يطابق هذا السطر فقط في الإدخال.
يمكن تحديد نطاق العنوان من خلال تحديد عناوين مفصولة بفاصلة (،).يتطابق نطاق العنوان الذي يبدأ من حيث يتطابق العنوان الأول ، ويستمر حتى يتطابق العنوان الثاني (بشكل شامل).
نصائح أخرى
sed -n '16224,16482 p' orig-data-file > new-file
حيث أن 16224,16482 هما رقم سطر البداية ورقم سطر النهاية شاملاً.هذا مفهرس. -n
يمنع تكرار المدخلات كمخرجات، وهو ما لا تريده بوضوح؛تشير الأرقام إلى نطاق الأسطر لتشغيل الأمر التالي؛الامر p
طباعة الخطوط ذات الصلة.
بسيط جدًا باستخدام الرأس/الذيل:
head -16482 in.sql | tail -258 > out.sql
باستخدام سيد:
sed -n '16482,16482p' in.sql > out.sql
باستخدام أوك:
awk 'NR>=10&&NR<=20' in.sql > out.sql
يمكنك استخدام "vi" ثم الأمر التالي:
:16224,16482w!/tmp/some-file
بدلاً عن ذلك:
cat file | head -n 16482 | tail -n 258
تعديل: - فقط لإضافة شرح، تستخدمه رئيس -ن 16482 لعرض أول 16482 سطرًا ثم استخدمه الذيل -ن 258 للحصول على آخر 258 سطرًا من الناتج الأول.
هناك نهج آخر مع awk
:
awk 'NR==16224, NR==16482' file
إذا كان الملف ضخمًا، فيمكن أن يكون جيدًا exit
بعد قراءة السطر الأخير المطلوب.بهذه الطريقة، لن يقرأ السطور التالية دون داع:
awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file
perl -ne 'print if 16224..16482' file.txt > new_file.txt
# print section of file based on line numbers
sed -n '16224 ,16482p' # method 1
sed '16224,16482!d' # method 2
sed -n '16224,16482p' < dump.sql
cat dump.txt | head -16224 | tail -258
يجب أن تفعل الخدعة.الجانب السلبي لهذا الأسلوب هو أنك تحتاج إلى إجراء العمليات الحسابية لتحديد وسيطة الذيل وحساب ما إذا كنت تريد أن يتضمن "المنتصف" سطر النهاية أم لا.
سريع و قذر:
head -16428 < file.in | tail -259 > file.out
ربما ليست أفضل طريقة للقيام بذلك ولكن يجب أن تنجح.
بالمناسبة:259 = 16482-16224+1.
لقد كتبت برنامج هاسكل يسمى الخائن هذا بالضبط ما يفعله:عند اقرأ من خلال منشور مدونة الإصدار الخاص بي.
يمكنك استخدام البرنامج على النحو التالي:
$ cat somefile | splitter 16224-16482
وهذا هو كل ما في الأمر.سوف تحتاج إلى هاسكل لتثبيته.فقط:
$ cabal install splitter
وقد انتهيت.آمل أن تجد هذا البرنامج مفيدا.
حتى يمكننا القيام بذلك للتحقق في سطر الأوامر:
cat filename|sed 'n1,n2!d' > abc.txt
على سبيل المثال:
cat foo.pl|sed '100,200!d' > abc.txt
باستخدام روبي:
ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf
أقف على أكتاف بوككسار، يعجبني هذا:
sed -n '<first line>,$p;<last line>q' input
على سبيل المثال
sed -n '16224,$p;16482q' input
ال $
يعني "السطر الأخير"، لذلك يصدر الأمر الأول sed
طباعة كافة الأسطر التي تبدأ بالسطر 16224
والأمر الثاني يجعل sed
يترك بعد خط الطباعة 16428
.(إضافة 1
ل q
- لا يبدو أن النطاق في حل boxxar ضروري.)
يعجبني هذا المتغير لأنني لست بحاجة إلى تحديد رقم سطر النهاية مرتين.وقمت بقياس ذلك باستخدام $
ليس لها آثار ضارة على الأداء.
كنت على وشك نشر خدعة الرأس/الذيل، لكن في الواقع كنت سأقوم بتشغيل emacs.؛-)
- خروج-س انتقل إلى الخط متقاعد 16224
- علامة (كنترول-فضاء)
- خروج-س انتقل إلى الخط متقاعد 16482
- خروج-ث
افتح ملف الإخراج الجديد ، CTL-Y Save
دعني أرى ما يحدث.
سأستخدم:
awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt
يحتوي FNR على رقم السجل (السطر) للخط الذي تتم قراءته من الملف.
لقد كتبت نصًا صغيرًا bash يمكنك تشغيله من سطر الأوامر الخاص بك، طالما قمت بتحديث PATH الخاص بك ليشمل دليله (أو يمكنك وضعه في دليل موجود بالفعل في PATH).
الاستخدام:$ قرصة اسم الملف، سطر البداية، سطر النهاية
#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon
FILENAME=$1
START=$2
END=$3
ERROR="[PINCH ERROR]"
# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
echo "$ERROR Need three arguments: Filename Start-line End-line"
exit 1
fi
# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
echo -e "$ERROR File does not exist. \n\t$FILENAME"
exit 1
fi
# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
echo -e "$ERROR Start line is greater than End line."
exit 1
fi
# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
echo -e "$ERROR Start line is less than 0."
exit 1
fi
# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
echo -e "$ERROR End line is less than 0."
exit 1
fi
NUMOFLINES=$(wc -l < "$FILENAME")
# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
echo -e "$ERROR End line is greater than number of lines in file."
exit 1
fi
# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))
# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
< "$FILENAME" head -n $END | tail -n +$START
else
< "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi
# Success
exit 0
قد يناسبك هذا (GNU sed):
sed -ne '16224,16482w newfile' -e '16482q' file
أو الاستفادة من باش:
sed -n $'16224,16482w newfile\n16482q' file
أردت أن أفعل نفس الشيء من برنامج نصي باستخدام متغير وحققت ذلك عن طريق وضع علامات الاقتباس حول المتغير $ لفصل اسم المتغير عن p:
sed -n "$first","$count"p imagelist.txt >"$imageblock"
كنت أرغب في تقسيم القائمة إلى مجلدات منفصلة ووجدت السؤال الأولي والإجابة خطوة مفيدة.(أمر الانقسام ليس خيارًا في نظام التشغيل القديم الذي يجب أن أقوم بنقل الرمز إليه).
يعمل -n في قبول الإجابات.إليك طريقة أخرى في حالة رغبتك.
cat $filename | sed "${linenum}p;d";
يقوم هذا بما يلي:
- قم بإدخال محتويات الملف (أو قم بتغذية النص بالطريقة التي تريدها).
- يقوم sed بتحديد السطر المحدد وطباعته
- مطلوب d لحذف الأسطر، وإلا فسوف يفترض sed أنه سيتم طباعة جميع الأسطر في النهاية.أي أنه بدون d، سوف تحصل على جميع الأسطر المطبوعة بواسطة السطر المحدد مطبوعة مرتين لأن لديك الجزء ${linenum}p الذي يطلب طباعته.أنا متأكد تمامًا من أن -n يفعل نفس الشيء مثل d هنا.
وبما أننا نتحدث عن استخراج أسطر نصية من ملف نصي، فسوف أعطي حالة خاصة حيث تريد استخراج جميع الأسطر التي تطابق نمطًا معينًا.
myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile
سيتم طباعة سطر [البيانات] والباقي.إذا كنت تريد النص من السطر 1 إلى النمط، فاكتب:sed -n '1,/Data/p' myfile.علاوة على ذلك، إذا كنت تعرف نمطين (من الأفضل أن يكونا فريدين في النص الخاص بك)، فيمكن تحديد كل من سطر البداية والنهاية للنطاق بالمطابقات.
sed -n '/BEGIN_MARK/,/END_MARK/p' myfile
أعتقد أن هذا قد يكون حلاً مفيدًا.إذا كان اسم الجدول هو "شخص"، فيمكنك استخدام sed للحصول على جميع الأسطر التي تحتاجها لاستعادة الجدول الخاص بك.
sed -n -e '/DROP TABLE IF EXISTS.*`person `/,/UNLOCK TABLES/p' data.sql > new_data.sql
مرتكز على هذه الإجابة, ، حيث يفتقد "DROP TABLE IF EXIST" للجدول الذي تقوم باستعادته وتحتاج إلى حذف بضعة أسطر من أسفل الملف الجديد قبل استخدامه لمنع حذف الجدول التالي.
ويمكن أيضا العثور على معلومات مفصلة هنا