كيف يمكنني إزالة لاحقة الملف والمسار جزء من مسار السلسلة في باش ؟
سؤال
وبالنظر إلى سلسلة مسار الملف مثل /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)
نقية باش يتم في عمليتين منفصلتين:
إزالة المسار من مسار السلسلة:
path=/foo/bar/bim/baz/file.gif file=${path##*/} #$file is now 'file.gif'
إزالة الملف من مسار السلسلة:
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