string - كيفية تقسيم سلسلة واحدة إلى سلاسل متعددة مفصولة بمسافة واحدة على الأقل في bash shell؟





split (7)


$ echo "This is   a sentence." | tr -s " " "\012"
This
is
a
sentence.

للتحقق من وجود مسافات ، استخدم grep:

$ echo "This is   a sentence." | grep " " > /dev/null
$ echo $?
0
$ echo "Thisisasentence." | grep " " > /dev/null     
$ echo $?
1

لدي سلسلة تحتوي على العديد من الكلمات مع مسافة واحدة على الأقل بين كل منهما. كيف يمكنني تقسيم السلسلة إلى كلمات فردية حتى أتمكن من تكرارها من خلالهم؟

يتم تمرير السلسلة كوسيطة. مثال ${2} == "cat cat file" . كيف يمكنني التكرار من خلاله؟

أيضا ، كيف يمكنني التحقق مما إذا كانت سلسلة تحتوي على مسافات؟




مجرد استخدام قذائف "مجموعة" مدمجة. فمثلا،

set $text

بعد ذلك ، ستكون الكلمات الفردية في نص $ $ 1 ، $ 2 ، $ 3 ، وما إلى ذلك

set -- junk $text
shift

للتعامل مع الحالة التي يكون فيها نص $ فارغًا أو يبدأ بشرطة. فمثلا:

text="This is          a              test"
set -- junk $text
shift
for word; do
  echo "[$word]"
done

هذا يطبع

[This]
[is]
[a]
[test]



هل حاولت فقط تمرير متغير السلسلة إلى حلقة for ؟ باش ، لأحد ، سوف ينقسم على المسافات التلقائية.

sentence="This is   a sentence."
for word in $sentence
do
    echo $word
done

This
is
a
sentence.



(أ) لتقسيم جملة إلى كلماتها (فاصلة بين الفضاءين) يمكنك ببساطة استخدام IFS الافتراضي باستخدام

array=( $string )


مثال على تشغيل المقتطف التالي

#!/bin/bash

sentence="this is the \"sentence\"   'you' want to split"
words=( $sentence )

len="${#words[@]}"
echo "words counted: $len"

printf "%s\n" "${words[@]}" ## print array

سوف يخرج

words counted: 8
this
is
the
"sentence"
'you'
want
to
split

كما ترون ، يمكنك استخدام اقتباسات مفردة أو مزدوجة أيضًا دون أي مشكلة

ملاحظات:
- هذا هو في الأساس نفس إجابة mob ، لكن بهذه الطريقة تخزن المصفوفة لأي حاجة أخرى. إذا كنت تحتاج فقط إلى حلقة واحدة ، يمكنك استخدام إجابته ، وهو سطر واحد أقصر :)
- يرجى الرجوع إلى هذا السؤال لطرق بديلة لتقسيم سلسلة استنادًا إلى محدد.


(ب) للتحقق من وجود حرف في سلسلة ، يمكنك أيضًا استخدام مطابقة التعبير العادي.
مثال للتحقق من وجود حرف مساحة يمكنك استخدامه:

regex='\s{1,}'
if [[ "$sentence" =~ $regex ]]
    then
        echo "Space here!";
fi



للتحقق من المساحات فقط مع bash:

[[ "$str" = "${str% *}" ]] && echo "no spaces" || echo "has spaces"



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

    sentence="this is a story"
    stringarray=($sentence)

الآن يمكنك الوصول إلى العناصر الفردية مباشرة (تبدأ بـ 0):

    echo ${stringarray[0]}

أو تحويلها مرة أخرى إلى سلسلة من الحلقات:

    for i in "${stringarray[@]}"
    do
      :
      # do whatever on $i
    done

وبالطبع تمت الإجابة على الحلقات من خلال السلسلة مباشرة من قبل ، ولكن هذه الإجابة كان لها العيب في عدم تعقب العناصر الفردية لاستخدامها لاحقًا:

    for i in $sentence
    do
      :
      # do whatever on $i
    done

راجع أيضًا مرجع Bash Array




في

[ -f "$file" ]

[ الأمر هو stat() (غير lstat() ) استدعاء النظام على المسار المخزن في $file وإرجاع true إذا نجح ذلك استدعاء النظام ونوع الملف كما تم إرجاعها بواسطة stat() هو "عادي".

لذا إذا عاد [ -f "$file" ] إلى true ، فيمكنك أن تقول أن الملف موجود وأنه عبارة عن ملف عادي أو رابط يرمز إليه في النهاية إلى ملف عادي (أو على الأقل كان في وقت إصدار stat() ).

ولكن إذا كانت ترجع false (أو إذا كان [ ! -f "$file" ] أو ! [ -f "$file" ] بإرجاع true) ، فهناك العديد من الاحتمالات المختلفة:

  • الملف غير موجود
  • الملف موجود ولكن ليس ملف عادي
  • الملف موجود ولكن ليس لديك إذن بحث إلى الدليل الأصل
  • الملف موجود ولكن هذا المسار للوصول إليه طويل جدًا
  • الملف عبارة عن رابط إلى ملف عادي ، ولكن ليس لديك إذن بحث لبعض الدلائل المتضمنة في حل الشفرة.
  • ... أي سبب آخر قد يفشل استدعاء النظام stat() .

باختصار ، يجب أن يكون:

if [ -f "$file" ]; then
  printf '"%s" is a path to a regular file or symlink to regular file\n' "$file"
elif [ -e "$file" ]; then
  printf '"%s" exists but is not a regular file\n' "$file"
elif [ -L "$file" ]; then
  printf '"%s" exists, is a symlink but I cannot tell if it eventually resolves to an actual file, regular or not\n' "$file"
else
  printf 'I cannot tell if "%s" exists, let alone whether it is a regular file or not\n' "$file"
fi

لكي نعرف على وجه اليقين أن الملف غير موجود ، سنحتاج إلى استدعاء النظام stat() مع رمز خطأ من ENOENT (يخبرنا ENOTDIR أحد مكونات المسار ليس دليلاً هو حالة أخرى يمكننا فيها معرفة الملف غير موجود في هذا المسار). لسوء الحظ ، لا يسمح لنا الأمر بمعرفة ذلك. سيعود كاذب ما إذا كان رمز الخطأ هو ENOENT أو EACCESS (تم رفض الإذن) أو ENAMETOOLONG أو أي شيء آخر.

يمكن أيضًا إجراء اختبار [ -e "$file" ] باستخدام ls -Ld -- "$file" > /dev/null . في هذه الحالة ، ls سبب فشل stat() ، على الرغم من أن المعلومات لا يمكن استخدامها بسهولة برمجيًا:

$ file=/var/spool/cron/crontabs/root
$ if [ ! -e "$file" ]; then echo does not exist; fi
does not exist
$ if ! ls -Ld -- "$file" > /dev/null; then echo stat failed; fi
ls: cannot access '/var/spool/cron/crontabs/root': Permission denied
stat failed

يقول لي على الأقل أنه ليس بسبب عدم وجود الملف الذي يفشل. لأنه لا يمكنه معرفة ما إذا كان الملف موجودًا أم لا. الأمر [ تجاهل المشكلة فقط.

باستخدام shell zsh ، يمكنك الاستعلام عن رمز الخطأ المتغير الخاص $ERRNO بعد فشل الأمر [ ، وفك ترميز ذلك باستخدام الصفيف الخاص $errnos في الوحدة النمطية zsh/system :

zmodload zsh/system
ERRNO=0
if [ ! -f "$file" ]; then
  err=$ERRNO
  case $errnos[err] in
    ("") echo exists, not a regular file;;
    (ENOENT|ENOTDIR)
       if [ -L "$file" ]; then
         echo broken link
       else
         echo does not exist
       fi;;
    (*) echo "can't tell"; syserror "$err"
  esac
fi

(حذار دعم $errnos مع بعض إصدارات zsh عند إنشاء الإصدارات الأخيرة من gcc ).





bash shell string split