Как сравнить строки в Bourne Shell?

Мне нужно сравнить строки в оболочке:

var1="mtu eth0"

if [ "$var1" == "mtu *" ]
then
    # do something
fi

Но очевидно, что «*» не работает в Shell. Есть ли способ сделать это?


person n-alexander    schedule 08.10.2008    source источник


Ответы (7)


bash

Кратчайшее исправление:

if [[ "$var1" = "mtu "* ]]

[[ ]] в Bash не расширяется, в отличие от [ ] (что должно происходить по историческим причинам).


bash --posix

О, я написал слишком быстро. Оболочка Bourne, а не Bash...

if [ "${var1:0:4}" == "mtu " ]

${var1:0:4} означает первые четыре символа $var1.


/bin/sh

Ах, извините. Эмуляция Bash POSIX не идет достаточно далеко; настоящая оригинальная оболочка Bourne не имеет ${var1:0:4}. Вам понадобится что-то вроде решения mstrobl.

if [ "$(echo "$var1" | cut -c0-4)" == "mtu " ]
person ephemient    schedule 08.10.2008
comment
${var1:0:4} -- откуда вы взяли этот синтаксис? Это определенно не POSIX. - person Roman Cheplyaka; 16.09.2011
comment
Моя версия cut говорит, что позиции нумеруются, начиная с 1. cut -c 1-4 или cut -c -4 здесь возвращают правильное значение. - person John Trammell; 26.01.2016
comment
В оболочке bourne/posix нет оператора ==; это =. - person jarno; 01.02.2020

Используйте инструменты Unix. Программа cut с удовольствием сократит строку.

if [ "$(echo $var1 | cut -c 4)" = "mtu " ];

... должен делать то, что вы хотите.

person mstrobl    schedule 08.10.2008
comment
Я считаю, что, поскольку вы сравниваете здесь две строки, это должно быть = или ==, а не -eq. - person Jim; 01.01.2014
comment
cut -c 4 вырезает четвертый символ: cut -c -4 вырезает первые четыре символа. - person John Trammell; 26.01.2016

Вы можете вызвать expr для сопоставления строк с регулярными выражениями из скриптов Bourne Shell. Ниже, кажется, работает:

#!/bin/sh

var1="mtu eth0"

if [ "`expr \"$var1\" : \"mtu .*\"`" != "0" ];then
  echo "match"
fi
person hasseg    schedule 08.10.2008

Мне нравится использовать оператор case для сравнения строк.

Тривиальный пример

case "$input"
in
  "$variable1") echo "matched the first value" 
     ;;
  "$variable2") echo "matched the second value"
     ;;
  *[a-z]*)  echo "input has letters" 
     ;;
  '')       echo "input is null!"
     ;;
   *[0-9]*)  echo "matched numbers (but I don't have letters, otherwise the letter test would have been hit first!)"
     ;;
   *) echo "Some wacky stuff in the input!"
esac

Я делал сумасшедшие вещи, такие как

case "$(cat file)"
in
  "$(cat other_file)")  echo "file and other_file are the same"
      ;;
  *)  echo "file and other_file are different"
esac

И это тоже работает, но с некоторыми ограничениями, например, файлы не могут быть больше пары мегабайт, а оболочка просто не видит пустых значений, поэтому, если в одном файле полно пустых значений, а в другом их нет (и ни у одного из них нет ничего другого), этот тест не увидит никакой разницы между ними.

Я не использую сравнение файлов в качестве серьезного примера, а только пример того, как оператор case способен выполнять гораздо более гибкое сопоставление строк, чем это доступно с помощью test или expr или других подобных выражений оболочки.

person chris    schedule 02.11.2009
comment
Это самый быстрый способ. - person jarno; 01.02.2020

Я бы сделал следующее:

# Removes anything but first word from "var1"
if [ "${var1%% *}" = "mtu" ] ; then ... fi

Or:

# Tries to remove the first word if it is "mtu", checks if we removed anything
if [ "${var1#mtu }" != "$var1" ] ; then ... fi
person ADEpt    schedule 08.10.2008
comment
Первый принимает строку без завершающего пробела. - person jarno; 01.02.2020

В оболочке Bourne, если я хочу проверить, содержит ли строка другую строку:

if [  `echo ${String} | grep -c ${Substr} ` -eq 1 ] ; then

Заключите echo ${String} | grep -c ${Substr} двумя обратными кавычками `:

Чтобы проверить, находится ли подстрока в начале или в конце:

if [ `echo ${String} | grep -c "^${Substr}"` -eq 1 ] ; then
...
if [ `echo ${String} | grep -c "${Substr}$"` -eq 1 ] ; then
person Community    schedule 08.02.2010

Или, например, оператор =~:

if [[ "$var1" =~ "mtu *" ]]
person ayaz    schedule 08.10.2008
comment
Bash 3.1 и выше имеет [[ a =~ .* ]]. Но * в кавычках неверно для версии 3.2 и выше без shopt -s compat31. - person ephemient; 09.10.2008
comment
Это не POSIX. - person Mateusz Piotrowski; 24.08.2017