Як стверджувати, що рядок має новий рядок, і, якщо так, видалити його


9

У мене є рядок, який є результатом якоїсь операції, над якою я не маю ніякого контролю. Коли я друкую цю змінну за допомогою echo, я отримую:

echo $myvar
hello

Однак коли я

if [ $myvar = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi

Я завжди розумію, що вони не рівні. Я підозрюю, що це через newlineхарактер.

Струна також веде себе дивно. Коли я роблю:

newVAR="this is my var twice: "$myvar$myvar
echo $newVAR

Я отримав:

hellois my var twice: hello

Як я можу перевірити, чи насправді це пов’язано з a, newlineі якщо так, видалити його?


1
У Bash ви можете printf '%q\n' "$string"отримати уникнуту версію будь-якого рядка. Наприклад: printf '%q\n' 'foo\n'-> foo\\n; printf '%q\n' $'foo\n'->$'foo\n'
l0b0

1
Ви не цитуєте розширення жодної зі змінних. Якби у них був якийсь пробільний пробіл, ви не побачили б це echo $foo. Зробіть echo "$foo"замість цього.
Пітер Кордес

Відповіді:


9

Проблема полягає в тому, що у вас є вбудована повернення перевезення (CR, \r). Це змушує точку введення тексту терміналу відштовхуватися до початку рядка, який він друкує. Ось чому ви бачите "привіт" на початку рядка у вашому $newVARприкладі - sed -n lвідображає читабельний вид недрукованих символів (та кінця рядка).

var=ab$'\r'c ; echo "$var";  printf %s "$var" | sed -n l
# output:
cb
ab\rc$

Ви можете перевірити це за допомогою простої перевірки стану баш:

[[ $var == *$'\r'* ]] && echo yes || echo no
# output:
yes

Ви можете об'єднати тест і виправити за один крок, випробувавши на \rних і видаливши їх за допомогою:

fix="${var//$'\r'/}"; echo "$var"; echo "$fix"
# output:
cb
abc

Для виправлення використовується розширення параметра Shell . Конкретна форма, що використовується вище, призначена для заміни підрядків, заснованих на вашому підтвердженому шаблоні: ${parameter/pattern/string}<- Це замінює лише перший знайдений шаблон на рядок із змінною, названою параметром *. Щоб замінити всі візерунки, потрібно просто змінити перший /на //.


Ви могли б пояснити свій останній біт коду? fix="....лінія?
farid99

@ farid99: пояснення додано у відповідь, Примітка fixможе бути varсама - або часто ви можете просто використовувати розширення параметра як є без необхідності перепризначати (можливо) змінене значення ..
Peter.O

5

Ви можете представляти \rяк $'\r'у bash:

if [ "$myvar" = "hello"$'\r' ]; then
    echo they are equal
else
    echo they are not equal
fi

Або подрібніть останнє \rв myvar:

if [ "${myvar%$'\r'*}" = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi

3

Цікаво, що в багатьох оболонках getoptsдуже вірогідний кандидат на таку роботу. Спочатку це може здатися протиінтуїтивним, але якщо ви вважаєте, що getopts"основна функція полягає в тому, щоб розпізнати та запропонувати для інтерпретації стільки заданих параметрів командного рядка одного символу, які можуть бути знайдені в одній і тій же зв'язаній серії, це може почати робити мало більше сенсу.

Для демонстрації з bashоболонки:

x=$(printf '\n\r%010s\t' hello)
OPTIND=1
while  getopts : na "-$x"
do     printf %q\\n "$OPTARG"
done

$'\n'
$'\r'
\
\
\
\
\
h
e
l
l
o
$'\t'

Таким чином іноді може бути зручно дозволити getoptsобробляти розбирання як своєрідний автопілот оболонки для подібних випадків. Коли ви це зробите, ви можете просто екранувати непотрібні байти w / a caseабо [протестувати ]і створити резервну копію рядка з байту 1:

OPTIND=1 y=$(printf \\n\\r) z=
while  getopts : na "-$x"
do     case $OPTARG in ([!$y])
            z=$z$OPTARG
       esac
done
printf %q\\n "$z"

$'     hello\t'

З огляду на цей простий приклад випадку - і надавши оболонку, яка підтримує розширення параметрів, що вже були згадані в іншому місці, - зазначені розширення, ймовірно, будуть служити вам тут краще. Але я подумав, getoptsщо варто також згадати, якщо ви не знали про його можливості в цьому відношенні. Звичайно, коли я дізнався про це, я все-таки знайшов для нього багато корисних додатків.


0

Хоча Bash та інші мови оболонок зручні, іноді краще використовувати справжню мову сценаріїв - наприклад Perl. Perl може замінити сценарії оболонки, які викликають інші мови, такі як sed і awk, а також команди UNIX досить легко. Я дізнався про це 20+ років тому, коли писав сценарії C-Shell, які, в свою чергу, називали sed, awk і різні команди UNIX - перед тим, як викликати код FORTRAN. У Перлі я би зробив:

chomp($myvar);   # removes the newline char

if("$myvar" eq "hello")   # string comparison
  {
  print "they are equal\n";
  }
else
  {
  print "they are not equal\n";
  }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.