it-swarm.asia

كيف تقليم مسافة بيضاء من متغير Bash؟

لديّ برنامج نصي من شل يحمل الرمز التالي:

var=`hg st -R "$path"`
if [ -n "$var" ]; then
    echo $var
fi

لكن يتم تنفيذ التعليمات البرمجية الشرطية دائمًا ، لأن hg st دائمًا يطبع حرف سطر واحد على الأقل.

  • هل هناك طريقة بسيطة لتجريد مسافة بيضاء من $var (مثل trim() في PHP

أو

  • هل هناك طريقة قياسية للتعامل مع هذه القضية؟

يمكنني استخدام sed أو AWK ، لكنني أعتقد أن هناك حلًا أكثر أناقة لهذه المشكلة.

770
too much php

دعنا نحدد متغيرًا يحتوي على مسافة بادئة ، زائدة ، ووسيطة:

FOO=' test test test '
echo -e "FOO='${FOO}'"
# > FOO=' test test test '
echo -e "length(FOO)==${#FOO}"
# > length(FOO)==16

كيفية إزالة جميع المسافات البيضاء (المشار إليها بواسطة [:space:] في tr):

FOO=' test test test '
FOO_NO_WHITESPACE="$(echo -e "${FOO}" | tr -d '[:space:]')"
echo -e "FOO_NO_WHITESPACE='${FOO_NO_WHITESPACE}'"
# > FOO_NO_WHITESPACE='testtesttest'
echo -e "length(FOO_NO_WHITESPACE)==${#FOO_NO_WHITESPACE}"
# > length(FOO_NO_WHITESPACE)==12

كيفية إزالة المسافة البادئة فقط:

FOO=' test test test '
FOO_NO_LEAD_SPACE="$(echo -e "${FOO}" | sed -e 's/^[[:space:]]*//')"
echo -e "FOO_NO_LEAD_SPACE='${FOO_NO_LEAD_SPACE}'"
# > FOO_NO_LEAD_SPACE='test test test '
echo -e "length(FOO_NO_LEAD_SPACE)==${#FOO_NO_LEAD_SPACE}"
# > length(FOO_NO_LEAD_SPACE)==15

كيفية إزالة مسافة بيضاء زائدة فقط:

FOO=' test test test '
FOO_NO_TRAIL_SPACE="$(echo -e "${FOO}" | sed -e 's/[[:space:]]*$//')"
echo -e "FOO_NO_TRAIL_SPACE='${FOO_NO_TRAIL_SPACE}'"
# > FOO_NO_TRAIL_SPACE=' test test test'
echo -e "length(FOO_NO_TRAIL_SPACE)==${#FOO_NO_TRAIL_SPACE}"
# > length(FOO_NO_TRAIL_SPACE)==15

كيفية إزالة كل من المسافات البادئة والزائدة - قم بسلسلة seds:

FOO=' test test test '
FOO_NO_EXTERNAL_SPACE="$(echo -e "${FOO}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
echo -e "FOO_NO_EXTERNAL_SPACE='${FOO_NO_EXTERNAL_SPACE}'"
# > FOO_NO_EXTERNAL_SPACE='test test test'
echo -e "length(FOO_NO_EXTERNAL_SPACE)==${#FOO_NO_EXTERNAL_SPACE}"
# > length(FOO_NO_EXTERNAL_SPACE)==14

بدلاً من ذلك ، إذا كان bash يدعمها ، فيمكنك استبدال echo -e "${FOO}" | sed ... بـ sed ... <<<${FOO} ، مثل ذلك (لمسافة بيضاء زائدة):

FOO_NO_TRAIL_SPACE="$(sed -e 's/[[:space:]]*$//' <<<${FOO})"
908
MattyV

الإجابة البسيطة هي:

echo "   lol  " | xargs

Xargs سوف تفعل التشذيب بالنسبة لك. إنه أمر واحد/برنامج ، لا توجد معلمات ، ويعيد السلسلة المشذبة ، بهذه السهولة!

ملاحظة: هذا لا يزيل المسافات الداخلية ، لذلك يبقى "foo bar" كما هو. لا يصبح "foobar".

792
makevoid

هناك حل يستخدم فقط Bash المضمنة تسمى _ ​​أحرف البدل:

var="    abc    "
# remove leading whitespace characters
var="${var#"${var%%[![:space:]]*}"}"
# remove trailing whitespace characters
var="${var%"${var##*[![:space:]]}"}"   
echo "===$var==="

هنا هو نفسه ملفوف في وظيفة:

trim() {
    local var="$*"
    # remove leading whitespace characters
    var="${var#"${var%%[![:space:]]*}"}"
    # remove trailing whitespace characters
    var="${var%"${var##*[![:space:]]}"}"   
    echo -n "$var"
}

يمكنك تمرير السلسلة ليتم قصها في النموذج المقتبس. على سبيل المثال:

trim "   abc   "

شيء جميل في هذا الحل هو أنه سيعمل مع أي قذيفة متوافقة مع POSIX.

مرجع

290
bashfu

يحتوي Bash على ميزة تسمى المعلمة التوسع ، والتي ، من بين أمور أخرى ، تسمح باستبدال السلسلة بناءً على ما يسمى الأنماط (تشبه الأنماط التعبيرات المعتادة ، ولكن هناك اختلافات وقيود أساسية). [السطر الأصلي من flussence: يحتوي Bash على تعبيرات منتظمة ، لكنها مخفية جيدًا:]

يوضح التالي كيفية إزالة الكل مساحة بيضاء (حتى من الداخل) من قيمة متغيرة.

$ var='abc def'
$ echo "$var"
abc def
# Note: flussence's original expression was "${var/ /}", which only replaced the *first* space char., wherever it appeared.
$ echo -n "${var//[[:space:]]/}"
abcdef
68
user42092

تجريد واحد الرائدة ومساحة زائدة واحدة

trim()
{
    local trimmed="$1"

    # Strip leading space.
    trimmed="${trimmed## }"
    # Strip trailing space.
    trimmed="${trimmed%% }"

    echo "$trimmed"
}

فمثلا:

test1="$(trim " one leading")"
test2="$(trim "one trailing ")"
test3="$(trim " one leading and one trailing ")"
echo "'$test1', '$test2', '$test3'"

انتاج:

'one leading', 'one trailing', 'one leading and one trailing'

الشريط جميع المساحات الرائدة والزائدة

trim()
{
    local trimmed="$1"

    # Strip leading spaces.
    while [[ $trimmed == ' '* ]]; do
       trimmed="${trimmed## }"
    done
    # Strip trailing spaces.
    while [[ $trimmed == *' ' ]]; do
        trimmed="${trimmed%% }"
    done

    echo "$trimmed"
}

فمثلا:

test4="$(trim "  two leading")"
test5="$(trim "two trailing  ")"
test6="$(trim "  two leading and two trailing  ")"
echo "'$test4', '$test5', '$test6'"

انتاج:

'two leading', 'two trailing', 'two leading and two trailing'
44
Brian Cain

لإزالة جميع المسافات من بداية ونهاية السلسلة (بما في ذلك أحرف نهاية السطر):

echo $variable | xargs echo -n

سيؤدي ذلك إلى إزالة المسافات المكررة أيضًا:

echo "  this string has a lot       of spaces " | xargs echo -n

تنتج: "هذه السلسلة لديها الكثير من المساحات"

40
rkachach

يمكنك القطع ببساطة باستخدام echo:

foo=" qsdqsd qsdqs q qs   "

# Not trimmed
echo \'$foo\'

# Trim
foo=`echo $foo`

# Trimmed
echo \'$foo\'
36
VAmp

من قسم دليل باش على التذويب

لاستخدام extglob في توسيع المعلمة

 #Turn on extended globbing  
shopt -s extglob  
 #Trim leading and trailing whitespace from a variable  
x=${x##+([[:space:]])}; x=${x%%+([[:space:]])}  
 #Turn off extended globbing  
shopt -u extglob  

هذه هي الوظيفة نفسها التي يتم لفها في دالة (ملاحظة: تحتاج إلى اقتباس سلسلة الإدخال التي تم تمريرها إلى الوظيفة):

trim() {
    # Determine if 'extglob' is currently on.
    local extglobWasOff=1
    shopt extglob >/dev/null && extglobWasOff=0 
    (( extglobWasOff )) && shopt -s extglob # Turn 'extglob' on, if currently turned off.
    # Trim leading and trailing whitespace
    local var=$1
    var=${var##+([[:space:]])}
    var=${var%%+([[:space:]])}
    (( extglobWasOff )) && shopt -u extglob # If 'extglob' was off before, turn it back off.
    echo -n "$var"  # Output trimmed string.
}

الاستعمال:

string="   abc def ghi  ";
#need to quote input-string to preserve internal white-space if any
trimmed=$(trim "$string");  
echo "$trimmed";

إذا قمنا بتغيير الوظيفة المراد تنفيذها في قشرة فرعية ، فلا داعي للقلق بشأن فحص خيار Shell الحالي ل extglob ، يمكننا فقط ضبطه دون التأثير على Shell الحالي. هذا يبسط وظيفة هائلة. أقوم أيضًا بتحديث المعلمات الموضعية "في المكان" حتى لا أحتاج إلى متغير محلي

trim() {
    shopt -s extglob
    set -- "${1##+([[:space:]])}"
    printf "%s" "${1%%+([[:space:]])}" 
}

وبالتالي:

$ s=$'\t\n \r\tfoo  '
$ shopt -u extglob
$ shopt extglob
extglob         off
$ printf ">%q<\n" "$s" "$(trim "$s")"
>$'\t\n \r\tfoo  '<
>foo<
$ shopt extglob
extglob         off
35
GuruM

مع تمكين ميزات مطابقة النمط الممتدة لـ Bash (shopt -s extglob) ، يمكنك استخدام هذا:

{trimmed##*( )}

لإزالة كمية تعسفية من المساحات الرائدة.

24
Mooshu

لقد فعلت دائما مع سيد

  var=`hg st -R "$path" | sed -e 's/  *$//'`

إذا كان هناك حل أكثر أناقة ، آمل أن يقوم شخص ما بنشره.

20
Paul Tomblin

يمكنك حذف الأسطر الجديدة مع tr:

var=`hg st -R "$path" | tr -d '\n'`
if [ -n $var ]; then
    echo $var
done
20
Adam Rosenfield
# Trim whitespace from both ends of specified parameter

trim () {
    read -rd '' $1 <<<"${!1}"
}

# Unit test for trim()

test_trim () {
    local foo="$1"
    trim foo
    test "$foo" = "$2"
}

test_trim hey hey &&
test_trim '  hey' hey &&
test_trim 'ho  ' ho &&
test_trim 'hey ho' 'hey ho' &&
test_trim '  hey  ho  ' 'hey  ho' &&
test_trim $'\n\n\t hey\n\t ho \t\n' $'hey\n\t ho' &&
test_trim $'\n' '' &&
test_trim '\n' '\n' &&
echo passed
17
flabdablet

هناك الكثير من الإجابات ، لكنني ما زلت أعتقد أن برنامجي المكتوب للتو يستحق الذكر لأنه:

  • تم اختباره بنجاح في shell bash/dash/busybox Shell
  • انها صغيرة للغاية
  • لا يعتمد على أوامر خارجية ولا يحتاج إلى مفترق (-> استخدام سريع ومنخفض للموارد)
  • يعمل كما هو متوقع:
    • يتم تجريد كافة المسافات وعلامات التبويب من البداية والنهاية ، ولكن ليس أكثر
    • مهم: لا يزيل أي شيء من منتصف السلسلة (العديد من الإجابات الأخرى تفعل) ، حتى الخطوط الجديدة ستبقى
    • special: "$*" ينضم إلى وسيطات متعددة باستخدام مساحة واحدة. إذا كنت تريد تقليم وإخراج الوسيطة الأولى فقط ، فاستخدم "$1" بدلاً من ذلك
    • إذا لم يكن لديه أي مشاكل في مطابقة أنماط أسماء الملفات وما إلى ذلك

النص:

trim() {
  local s2 s="$*"
  # note: the brackets in each of the following two lines contain one space
  # and one tab
  until s2="${s#[   ]}"; [ "$s2" = "$s" ]; do s="$s2"; done
  until s2="${s%[   ]}"; [ "$s2" = "$s" ]; do s="$s2"; done
  echo "$s"
}

الاستعمال:

mystring="   here     is
    something    "
mystring=$(trim "$mystring")
echo ">$mystring<"

انتاج:

>here     is
    something<
11
Daniel Alder

يمكنك استخدام المدرسة القديمة tr. على سبيل المثال ، يؤدي هذا إلى إرجاع عدد الملفات التي تم تعديلها في مستودع git ، حيث يتم تجريد المسافات البيضاء.

MYVAR=`git ls-files -m|wc -l|tr -d ' '`
11
pojo

هذا عملت لي:

text="   trim my edges    "

trimmed=$text
trimmed=${trimmed##+( )} #Remove longest matching series of spaces from the front
trimmed=${trimmed%%+( )} #Remove longest matching series of spaces from the back

echo "<$trimmed>" #Adding angle braces just to make it easier to confirm that all spaces are removed

#Result
<trim my edges>

لوضع ذلك على عدد أقل من الخطوط لنفس النتيجة:

text="    trim my edges    "
trimmed=${${text##+( )}%%+( )}
9
gMale
# Strip leading and trailing white space (new line inclusive).
trim(){
    [[ "$1" =~ [^[:space:]](.*[^[:space:]])? ]]
    printf "%s" "$BASH_REMATCH"
}

OR

# Strip leading white space (new line inclusive).
ltrim(){
    [[ "$1" =~ [^[:space:]].* ]]
    printf "%s" "$BASH_REMATCH"
}

# Strip trailing white space (new line inclusive).
rtrim(){
    [[ "$1" =~ .*[^[:space:]] ]]
    printf "%s" "$BASH_REMATCH"
}

# Strip leading and trailing white space (new line inclusive).
trim(){
    printf "%s" "$(rtrim "$(ltrim "$1")")"
}

OR

# Strip leading and trailing specified characters.  ex: str=$(trim "$str" $'\n a')
trim(){
    if [ "$2" ]; then
        trim_chrs="$2"
    else
        trim_chrs="[:space:]"
    fi

    [[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
    printf "%s" "${BASH_REMATCH[1]}"
}

OR

# Strip leading specified characters.  ex: str=$(ltrim "$str" $'\n a')
ltrim(){
    if [ "$2" ]; then
        trim_chrs="$2"
    else
        trim_chrs="[:space:]"
    fi

    [[ "$1" =~ ^["$trim_chrs"]*(.*[^"$trim_chrs"]) ]]
    printf "%s" "${BASH_REMATCH[1]}"
}

# Strip trailing specified characters.  ex: str=$(rtrim "$str" $'\n a')
rtrim(){
    if [ "$2" ]; then
        trim_chrs="$2"
    else
        trim_chrs="[:space:]"
    fi

    [[ "$1" =~ ^(.*[^"$trim_chrs"])["$trim_chrs"]*$ ]]
    printf "%s" "${BASH_REMATCH[1]}"
}

# Strip leading and trailing specified characters.  ex: str=$(trim "$str" $'\n a')
trim(){
    printf "%s" "$(rtrim "$(ltrim "$1" "$2")" "$2")"
}

OR

بناء على المسكوت.

# Strip leading and trailing white space (new line inclusive).
trim(){
    printf "%s" "`expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)[[:space:]]*$"`"
}

OR

# Strip leading white space (new line inclusive).
ltrim(){
    printf "%s" "`expr "$1" : "^[[:space:]]*\(.*[^[:space:]]\)"`"
}

# Strip trailing white space (new line inclusive).
rtrim(){
    printf "%s" "`expr "$1" : "^\(.*[^[:space:]]\)[[:space:]]*$"`"
}

# Strip leading and trailing white space (new line inclusive).
trim(){
    printf "%s" "$(rtrim "$(ltrim "$1")")"
}
9
NOYB

لقد رأيت البرامج النصية مجرد استخدام الواجب المتغير للقيام بهذه المهمة:

$ xyz=`echo -e 'foo \n bar'`
$ echo $xyz
foo bar

يتم دمج مساحة اللون الأبيض تلقائيًا وتقليصها. يتعين على المرء أن يكون حذراً من metacharacters Shell (خطر الحقن المحتملة).

أود أن أوصي دائمًا بالتبديل المزدوج للبدائل المتغيرة في الشرطية الشرطية:

if [ -n "$var" ]; then

نظرًا لأن هناك ما يشبه a -o أو أي محتوى آخر في المتغير يمكن أن يعدل وسيطات الاختبار الخاصة بك.

8
MykennaC
var='   a b c   '
trimmed=$(echo $var)
7
ultr

أود ببساطة استخدام sed:

function trim
{
    echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'
}

a) مثال للاستخدام على سلسلة سطر واحد

string='    wordA wordB  wordC   wordD    '
trimmed=$( trim "$string" )

echo "GIVEN STRING: |$string|"
echo "TRIMMED STRING: |$trimmed|"

انتاج:

GIVEN STRING: |    wordA wordB  wordC   wordD    |
TRIMMED STRING: |wordA wordB  wordC   wordD|

ب) مثال للاستخدام على سلسلة متعددة الخطوط

string='    wordA
   >wordB<
wordC    '
trimmed=$( trim "$string" )

echo -e "GIVEN STRING: |$string|\n"
echo "TRIMMED STRING: |$trimmed|"

انتاج:

GIVEN STRING: |    wordAA
   >wordB<
wordC    |

TRIMMED STRING: |wordAA
   >wordB<
wordC|

ج) الملاحظة النهائية:
إذا كنت لا ترغب في استخدام وظيفة ، من أجل سلسلة سطر واحد يمكنك ببساطة استخدام أمر "أسهل للتذكر" مثل:

echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'

مثال:

echo "   wordA wordB wordC   " | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'

انتاج:

wordA wordB wordC

باستخدام ما ورد أعلاه على ستعمل السلاسل المتعددة الأسطر بشكل جيد ، ولكن يرجى ملاحظة أنه سيؤدي إلى تقليل أي مساحة زائدة داخلية متعددة/زائدة أيضًا ، كما لاحظت GuruM في التعليقات

string='    wordAA
    >four spaces before<
 >one space before<    '
echo "$string" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//'

انتاج:

wordAA
>four spaces before<
>one space before<

إذا كنت تمانع في الحفاظ على هذه المساحات ، يرجى استخدام الوظيفة في بداية جوابي!

د) شرح بناء جملة sed "find and replace" على سلاسل متعددة الأسطر تستخدم داخل تقليم الوظيفة:

sed -n '
# If the first line, copy the pattern to the hold buffer
1h
# If not the first line, then append the pattern to the hold buffer
1!H
# If the last line then ...
$ {
    # Copy from the hold to the pattern buffer
    g
    # Do the search and replace
    s/^[ \t]*//g
    s/[ \t]*$//g
    # print
    p
}'
7
Luca Borrione

تتجاهل الواجبات المسافة البادئة والزائدة ، وبالتالي يمكن استخدامها للتقليم:

$ var=`echo '   hello'`; echo $var
hello
6
evanx

لإزالة المسافات وعلامات التبويب من اليسار إلى أول كلمة ، أدخل:

echo "     This is a test" | sed "s/^[ \t]*//"

cyberciti.biz/tips/delete-leading-spaces-from-front-of-each-Word.html

5
Steven Penny

فيما يلي وظيفة تقليم () تعمل على خفض المسافة البيضاء وتطبيعها

#!/bin/bash
function trim {
    echo $*
}

echo "'$(trim "  one   two    three  ")'"
# 'one two three'

و متغير آخر يستخدم تعبيرات منتظمة.

#!/bin/bash
function trim {
    local trimmed="[email protected]"
    if [[ "$trimmed" =~ " *([^ ].*[^ ]) *" ]]
    then 
        trimmed=${BASH_REMATCH[1]}
    fi
    echo "$trimmed"
}

echo "'$(trim "  one   two    three  ")'"
# 'one   two    three'
5
Nicholas Sushkin

استخدم AWK:

echo $var | awk '{gsub(/^ +| +$/,"")}1'
5
ghostdog74

سيؤدي ذلك إلى إزالة جميع المسافات البيضاء من السلسلة الخاصة بك ،

 VAR2="${VAR2//[[:space:]]/}"

/ يستبدل التكرار الأول و // جميع تكرارات المسافات البيضاء في السلسلة. أي. الحصول على استبدال جميع المساحات البيضاء - لا شيء

4
Alpesh Gediya

هذه هي أبسط طريقة رأيتها. إنه يستخدم Bash فقط ، إنه فقط بضعة أسطر ، regexp بسيط ، وهو يطابق كل أشكال المسافة البيضاء:

if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
then 
    test=${BASH_REMATCH[1]}
fi

فيما يلي نموذج نصي لاختباره باستخدام:

test=$(echo -e "\n \t Spaces and tabs and newlines be gone! \t  \n ")

echo "Let's see if this works:"
echo
echo "----------"
echo -e "Testing:${test} :Tested"  # Ugh!
echo "----------"
echo
echo "Ugh!  Let's fix that..."

if [[ "$test" =~ ^[[:space:]]*([^[:space:]].*[^[:space:]])[[:space:]]*$ ]]
then 
    test=${BASH_REMATCH[1]}
fi

echo
echo "----------"
echo -e "Testing:${test}:Tested"  # "Testing:Spaces and tabs and newlines be gone!"
echo "----------"
echo
echo "Ah, much better."
4
blujay

لا توجد مشكلة في هذا التخطي غير المرغوب فيه ، أيضًا ، المساحة البيضاء الداخلية غير معدّلة (على افتراض أن $IFS مضبوط على الافتراضي ، وهو ' \t\n').

يقرأ حتى السطر الأول الجديد (ولا يتضمنه) أو نهاية السلسلة ، أيهما يأتي أولاً ، ويقوم بشطب أي مزيج من المسافة البادئة والزائدة والحروف \t. إذا كنت ترغب في الحفاظ على خطوط متعددة (وأيضًا تجريد الخطوط الأمامية والخلفية) ، استخدم read -r -d '' var << eof بدلاً من ذلك ؛ مع ذلك ، لاحظ أنه إذا حدث أن يحتوي الإدخال على \neof ، فسيتم إيقافه قبل ذلك. (الأشكال الأخرى من المساحة البيضاء ، وهي \r و \f و \v ، هي لا مجردة ، حتى لو قمت بإضافتها إلى IFS $.)

read -r var << eof
$var
eof
4
Gregor

لدى Python وظيفة strip() تعمل بشكل مماثل لـ PHP's trim() ، حتى نتمكن من القيام بقليل من مضمون Python لتقديم أداة سهلة الفهم لهذا:

alias trim='python -c "import sys; sys.stdout.write(sys.stdin.read().strip())"'

سيؤدي ذلك إلى تقليل المسافة البادئة والزائدة (بما في ذلك الخطوط الجديدة).

$ x=`echo -e "\n\t   \n" | trim`
$ if [ -z "$x" ]; then echo hi; fi
hi
3
brownhead

يزيل trim () المسافات البيضاء (وعلامات التبويب والأحرف غير القابلة للطباعة ؛ أنا أفكر فقط في المسافات البيضاء للبساطة). روايتي للحل:

var="$(hg st -R "$path")" # I often like to enclose Shell output in double quotes
var="$(echo "${var}" | sed "s/\(^ *\| *\$\)//g")" # This is my suggestion
if [ -n "$var" ]; then
 echo "[${var}]"
fi

يعمل الأمر 'sed' على قطع مسافات المسافات البادئة والزائدة فقط ، ولكن يمكن توجيهها إلى الأمر الأول مما يؤدي إلى:

var="$(hg st -R "$path" | sed "s/\(^ *\| *\$\)//g")"
if [ -n "$var" ]; then
 echo "[${var}]"
fi
3
Avenger
#!/bin/bash

function trim
{
    typeset trimVar
    eval trimVar="\${$1}"
    read trimVar << EOTtrim
    $trimVar
EOTtrim
    eval $1=\$trimVar
}

# Note that the parameter to the function is the NAME of the variable to trim, 
# not the variable contents.  However, the contents are trimmed.


# Example of use:
while read aLine
do
    trim aline
    echo "[${aline}]"
done < info.txt



# File info.txt contents:
# ------------------------------
# ok  hello there    $
#    another  line   here     $
#and yet another   $
#  only at the front$
#$



# Output:
#[ok  hello there]
#[another  line   here]
#[and yet another]
#[only at the front]
#[]
3
Razor5900

لقد وجدت أنني بحاجة إلى إضافة بعض التعليمات البرمجية من إخراج sdiff لتنظيفه:

sdiff -s column1.txt column2.txt | grep -F '<' | cut -f1 -d"<" > c12diff.txt 
sed -n 1'p' c12diff.txt | sed 's/ *$//g' | tr -d '\n' | tr -d '\t'

هذا يزيل المسافات الزائدة والشخصيات غير المرئية الأخرى.

3
user1186515

استعمال:

trim() {
    local orig="$1"
    local trmd=""
    while true;
    do
        trmd="${orig#[[:space:]]}"
        trmd="${trmd%[[:space:]]}"
        test "$trmd" = "$orig" && break
        orig="$trmd"
    done
    printf -- '%s\n' "$trmd"
}
  • يعمل على جميع أنواع المسافات البيضاء ، بما في ذلك السطر الجديد ،
  • أنها لا تحتاج إلى تعديل shopt.
  • إنه يحافظ على مساحة بيضاء ، بما في ذلك السطر الجديد.

اختبار الوحدة (للمراجعة اليدوية):

#!/bin/bash

. trim.sh

enum() {
    echo "   a b c"
    echo "a b c   "
    echo "  a b c "
    echo " a b c  "
    echo " a  b c  "
    echo " a  b  c  "
    echo " a      b  c  "
    echo "     a      b  c  "
    echo "     a  b  c  "
    echo " a  b  c      "
    echo " a  b  c      "
    echo " a N b  c  "
    echo "N a N b  c  "
    echo " Na  b  c  "
    echo " a  b  c N "
    echo " a  b  c  N"
}

xcheck() {
    local testln result
    while IFS='' read testln;
    do
        testln=$(tr N '\n' <<<"$testln")
        echo ": ~~~~~~~~~~~~~~~~~~~~~~~~~ :" >&2
        result="$(trim "$testln")"
        echo "testln='$testln'" >&2
        echo "result='$result'" >&2
    done
}

enum | xcheck
3
Alois Mahdal

أنا خلقت الوظائف التالية. لست متأكدًا من مدى قابلية printf المحمولة ، لكن جمال هذا الحل هو أنه يمكنك تحديد "المساحة البيضاء" بالضبط عن طريق إضافة المزيد من رموز الأحرف.

    iswhitespace()
    {
        n=`printf "%d\n" "'$1'"`
        if (( $n != "13" )) && (( $n != "10" )) && (( $n != "32" )) && (( $n != "92" )) && (( $n != "110" )) && (( $n != "114" )); then
            return 0
        fi
        return 1
    }

    trim()
    {
        i=0
        str="$1"
        while (( i < ${#1} ))
        do
            char=${1:$i:1}
            iswhitespace "$char"
            if [ "$?" -eq "0" ]; then
                str="${str:$i}"
                i=${#1}
            fi
            (( i += 1 ))
        done
        i=${#str}
        while (( i > "0" ))
        do
            (( i -= 1 ))
            char=${str:$i:1}
            iswhitespace "$char"
            if [ "$?" -eq "0" ]; then
                (( i += 1 ))
                str="${str:0:$i}"
                i=0
            fi
        done
        echo "$str"
    }

#Call it like so
mystring=`trim "$mystring"`
3
cmeub

إزالة المسافات إلى مساحة واحدة:

(text) | fmt -su
2
gardziol

كنت بحاجة إلى قطع مسافة بيضاء من برنامج نصي عندما تم تعيين متغير IFS إلى شيء آخر. الاعتماد على بيرل فعل الخدعة:

# trim() { echo $1; } # This doesn't seem to work, as it's affected by IFS

trim() { echo "$1" | Perl -p -e 's/^\s+|\s+$//g'; }

strings="after --> , <-- before,  <-- both -->  "

OLD_IFS=$IFS
IFS=","
for str in ${strings}; do
  str=$(trim "${str}")
  echo "str= '${str}'"
done
IFS=$OLD_IFS
2
TrinitronX
var="  a b  "
echo "$(set -f; echo $var)"

>a b
2
davide

استخدم هذا Bash البسيط توسيع المعلمة :

$ x=" a z     e r ty "
$ echo "START[${x// /}]END"
START[azerty]END
2
Gilles Quenot

استعمال:

var=`expr "$var" : "^\ *\(.*[^ ]\)\ *$"`

إنه يزيل المساحات الأمامية والخلفية وهو الحل الأساسي ، على ما أعتقد. ليس Bash مضمنًا ، ولكن "expr" جزء من اللبنات ، لذلك على الأقل لا توجد حاجة إلى أدوات مساعدة مستقلة مثل sed أو AWK .

2
moskit

هذا الديكورات مسافات متعددة من الأمام والنهاية

whatever=${whatever%% *}

whatever=${whatever#* }

2
gretelmk2

بعد حل آخر مع اختبارات الوحدة الذي يحرك $IFS من stdin ، ويعمل مع أي فاصل الإدخال (حتى $'\0'):

ltrim()
{
    # Left-trim $IFS from stdin as a single line
    # $1: Line separator (default NUL)
    local trimmed
    while IFS= read -r -d "${1-}" -u 9
    do
        if [ -n "${trimmed+defined}" ]
        then
            printf %s "$REPLY"
        else
            printf %s "${REPLY#"${REPLY%%[!$IFS]*}"}"
        fi
        printf "${1-\x00}"
        trimmed=true
    done 9<&0

    if [[ $REPLY ]]
    then
        # No delimiter at last line
        if [ -n "${trimmed+defined}" ]
        then
            printf %s "$REPLY"
        else
            printf %s "${REPLY#"${REPLY%%[!$IFS]*}"}"
        fi
    fi
}

rtrim()
{
    # Right-trim $IFS from stdin as a single line
    # $1: Line separator (default NUL)
    local previous last
    while IFS= read -r -d "${1-}" -u 9
    do
        if [ -n "${previous+defined}" ]
        then
            printf %s "$previous"
            printf "${1-\x00}"
        fi
        previous="$REPLY"
    done 9<&0

    if [[ $REPLY ]]
    then
        # No delimiter at last line
        last="$REPLY"
        printf %s "$previous"
        if [ -n "${previous+defined}" ]
        then
            printf "${1-\x00}"
        fi
    else
        last="$previous"
    fi

    right_whitespace="${last##*[!$IFS]}"
    printf %s "${last%$right_whitespace}"
}

trim()
{
    # Trim $IFS from individual lines
    # $1: Line separator (default NUL)
    ltrim ${1+"[email protected]"} | rtrim ${1+"[email protected]"}
}
1
l0b0