Как проверить строки на лексикографию, меньшую или равную в Bash?

В Bash существует ли простой способ проверить, является ли одна строка лексикографически меньшей или равной другой?

Я знаю, что вы можете сделать:

if [[ "a" < "b" ]]

для тестирования строгого неравенства или

if [[ 1 -le 1 ]]

для чисел. Но -le, похоже, не работает со строками, а использование <= дает синтаксическую ошибку.

Ответ 1

Просто отрицайте значение, отличное от теста:

if [[ ! "a" > "b" ]]

Ответ 2

Вам нужно использовать || с дополнительным условием вместо <=:

[[ "$a" < "$b" || "$a" == "$b" ]] 

Ответ 3

Вы можете перевернуть сравнение и подписать и проверить отрицательно:

$ a="abc"
$ b="abc"
$ if ! [[ "$b" > "$a" ]] ; then  echo "a <= b" ; fi
a <= b

Если вам нужна последовательность сортировки "A", тогда "a", затем "B"... используйте:

shopt -s nocaseglob

Ответ 4

Если вы можете использовать синтаксис Bash, посмотрите ответы @anubhava и @gordon-davisson. С синтаксисом POSIX у вас есть две опции (обратите внимание на необходимые обратные слеши!):

используя оператор -o (OR):

[ "$a" \< "$b" -o "$a" = "$b" ] && echo "'$a' LTE '$b'" || echo "'$a' GT '$b'"

или используя отрицание:

[ ! "$a" \> "$b" ] && echo "'$a' LTE '$b'" || echo "'$a' GT '$b'"

Я предпочитаю первый вариант, потому что имхо он более читабелен.

Ответ 5

метод expr POSIX

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expr.html

[ "$(expr abc \< acb)" = 1 ] || echo fail
[ "$(expr abc \< aac)" = 0 ] || echo fail

POSIX говорит, что expr определяет, является ли аргумент целочисленной или общей строкой, и сравнивает ли строка:

возвращает результат сравнения строк с использованием последовательности сопоставления для конкретной локали

sort POSIX обходной путь

Просто для удовольствия, используйте вместо этого expr.

Не бесконечно устойчивы к строкам с символами новой строки, но когда это когда-либо происходит при работе со скриптами оболочки?

string_lte() (
  s="$(printf "${1}\n${2}")"
  if [ "$(printf "$s" | sort)" = "$s" ]; then
    exit 0
  else
    exit 1
  fi
)
string_lte abc adc || echo fail
string_lte adc adc || echo fail
string_lte afc adc && echo fail