كيف يمكنني إزالة لاحقة الملف والمسار جزء من مسار السلسلة في باش ؟

StackOverflow https://stackoverflow.com/questions/125281

  •  02-07-2019
  •  | 
  •  

سؤال

وبالنظر إلى سلسلة مسار الملف مثل /foo/fizzbuzz.bar, كيف يمكنني استخدام باش لاستخراج فقط fizzbuzz جزء من السلسلة ؟

هل كانت مفيدة؟

المحلول

هنا هو كيف نفعل ذلك مع # و % منظم باش.

$ x="/foo/fizzbuzz.bar"
$ y=${x%.bar}
$ echo ${y##*/}
fizzbuzz

${x%.bar} يمكن أن يكون أيضا ${x%.*} إلى إزالة كل شيء بعد نقطة أو ${x%%.*} إلى إزالة كل شيء بعد أول نقطة.

على سبيل المثال:

$ x="/foo/fizzbuzz.bar.quux"
$ y=${x%.*}
$ echo $y
/foo/fizzbuzz.bar
$ y=${x%%.*}
$ echo $y
/foo/fizzbuzz

ويمكن الاطلاع على وثائق في باش دليل.البحث عن ${parameter%word} و ${parameter%%word} زائدة جزء مطابقة القسم.

نصائح أخرى

نظرة على basename الأمر:

NAME=$(basename /foo/fizzbuzz.bar .bar)

نقية باش يتم في عمليتين منفصلتين:

  1. إزالة المسار من مسار السلسلة:

    path=/foo/bar/bim/baz/file.gif
    
    file=${path##*/}  
    #$file is now 'file.gif'
    
  2. إزالة الملف من مسار السلسلة:

    base=${file%.*}
    #${base} is now 'file'.
    

باستخدام basename اعتدت التالية لتحقيق ذلك:

for file in *; do
    ext=${file##*.}
    fname=`basename $file $ext`

    # Do things with $fname
done;

هذا لا يتطلب بداهة معرفة امتداد الملف يعمل حتى عندما يكون لديك اسم الملف الذي يحتوي النقاط في اسم الملف (في الجبهة من التمديد);فإنه لا يتطلب البرنامج basename ولكن هذا هو جزء من جنو coreutils لذلك يجب أن السفينة مع أي توزيعة.

نقية باش الطريقة:

~$ x="/foo/bar/fizzbuzz.bar.quux.zoom"; 
~$ y=${x/\/*\//}; 
~$ echo ${y/.*/}; 
fizzbuzz

هذه الوظيفة هو شرح على الرجل باش تحت عنوان "المعلمة التوسع".غير باش طرق كثيرة:أوك, perl, sed وهلم جرا.

تحرير:يعمل مع النقاط في الملف اللواحق و لا تحتاج إلى معرفة لاحقة (التمديد) ، ولكن لا العمل مع النقاط في اسم نفسها.

على basename و dirname الوظائف ما كنت بعد:

mystring=/foo/fizzbuzz.bar
echo basename: $(basename "${mystring}")
echo basename + remove .bar: $(basename "${mystring}" .bar)
echo dirname: $(dirname "${mystring}")

وقد الإخراج:

basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo
perl -pe 's/\..*$//;s{^.*/}{}'

باستخدام basename يفترض أن تعرف ما امتداد الملف هو, أليس كذلك ؟

وأعتقد أن مختلف التعبير العادي اقتراحات لا التعامل مع الملف يحتوي على أكثر من واحد "."

ما يلي يبدو أن التعامل مع مضاعفة النقاط.أوه, و أسماء الملفات التي تحتوي على "/" أنفسهم (للتسلية فقط)

على حد تعبير باسكال "آسف هذا السيناريو هو وقتا طويلا.لم يكن لدي الوقت لجعله أقصر"


  #!/usr/bin/perl
  $fullname = $ARGV[0];
  ($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
  ($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
  print $basename . "\n";
 

إذا لم تتمكن من استخدام basename كما اقترح في وظائف أخرى, يمكنك دائما استخدام sed.هنا هو (القبيح) على سبيل المثال.فإنه ليس أعظم ، ولكنه يعمل عن طريق استخراج أراد سلسلة استبدال الإدخال مع أردت السلسلة.

echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'

والتي سوف تحصل على الناتج

fizzbuzz

بالإضافة إلى POSIX conformant الجملة المستخدمة في هذا الجواب,

basename سلسلة [لاحقة]

كما في

basename /foo/fizzbuzz.bar .bar

جنو basename يدعم آخر الجملة:

basename -s .bar /foo/fizzbuzz.bar

مع نفس النتيجة.الفرق و ميزة هي أن -s يعني -a, الذي يدعم العديد من الحجج:

$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar
fizzbuzz
foobar

حتى هذا يمكن أن يكون اسم الملف آمنة خلال فصل الإنتاج NUL بايت باستخدام -z الخيار, على سبيل المثال هذه الملفات التي تحتوي على الفراغات أسطر و غلوب الشخصيات (نقلا عن ls):

$ ls has*
'has'$'\n''newline.bar'  'has space.bar'  'has*.bar'

قراءة في مجموعة:

$ readarray -d $'\0' arr < <(basename -zs .bar has*)
$ declare -p arr
declare -a arr=([0]=$'has\nnewline' [1]="has space" [2]="has*")

readarray -d يتطلب باش 4.4 أو أحدث.للإصدارات القديمة ، علينا أن الحلقة:

while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)

حذار من اقترح بيرل الحل:فهو يزيل أي شيء بعد أول نقطة.

$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some

إذا كنت تريد أن تفعل ذلك مع بيرل ، يعمل هذا:

$ echo some.file.with.dots | perl -pe 's/(.*)\..*$/$1/;s{^.*/}{}'
some.file.with

ولكن إذا كنت تستخدم باش الحلول مع y=${x%.*} (أو basename "$x" .ext إذا كنت تعرف التمديد) هي أبسط من ذلك بكثير.

على basename لا أنه يزيل المسار.فإنه سيتم أيضا إزالة لاحقة إذا ما أعطيت و إذا كان يتطابق لاحقة الملف ولكن كنت بحاجة إلى معرفة لاحقة لإعطاء الأوامر.خلاف ذلك يمكنك استخدام mv و معرفة ما اسم جديد يجب أن يكون بطريقة أخرى.

والجمع بين أعلى تصنيف الإجابة مع ثاني أعلى تصنيف إجابة للحصول على اسم الملف دون المسار الكامل:

$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top