Shell :Проверка наличия в строке заданного символа

Библиотеки XMLSECURITY

# yum search xmlsec
.    
  xmlsec1
  xmlsec1-devel
  xmlsec1-gcrypt
  xmlsec1-gcrypt-devel
  xmlsec1-gnutls
  xmlsec1-gnutls-devel
  xmlsec1-nss
  xmlsec1-nss-devel
  xmlsec1-openssl
  xmlsec1-openssl-devel

В списке строк -http://mirror.centos.org/altarch/7.4.1708/os/i386/Packages/

Пример установки:# yum install xmlsec1-devel

-1
21.12.2020, 21:29
2 ответа

Основная проблема заключается в том, что вы используете сопоставление с образцом в [[... ]]в сценарии, выполняемом /bin/sh, который не поддерживает эти типы тестов. См. также вопрос, озаглавленный Сценарий оболочки выдает ошибку «не найдено» при запуске из файла sh. Но при ручном вводе команды работают

Другая проблема заключается в том, что вы объединяете вывод lsв одну строку, прежде чем разбивать ее на слова по пробелам, табуляциям и символам новой строки, а также применять подстановку имен файлов к сгенерированным словам. Затем вы перебираете результат этого.

Вместо:

#!/bin/sh

cd Folder || exit 1

for name in *b*; do
    [ -e "$name" ] || [ -L "$name" ] || continue
    case $name in (*a*) ;; (*) printf '%s\n' "$name"; esac
done

Это перебирает все файлы в каталоге Folder, в которых есть буква b, а затем печатает те из них, которые не содержат a. Проверка символа aвыполняется с помощью case... esac.Шаблон *a*соответствует символу aв имени файла, если он есть, и в этом случае ничего не происходит. Операторы printfнаходятся в «случай по умолчанию», который выполняется, если в строке нет a.

Тесты с -eи -Lнужны для того, чтобы убедиться, что мы поймаем пограничный случай, когда шаблон цикла ничему не соответствует. В этом случае шаблон останется нерасширенным, поэтому, чтобы убедиться, что мы можем отличить нерасширенный шаблон от реального существующего файла, мы проверяем его с помощью -e. Тест -Lсостоит в том, чтобы поймать еще один пограничный случай символической ссылки, которая имеет то же имя, что и шаблон цикла, но не указывает ни на что допустимое. Приведенный ниже код bashне нуждается в этом, потому что он использует параметр оболочки nullglobвместо (, недоступного в /bin/sh).

Запуск цикла по расширению шаблона *b*вместо любого результата lsимеет то преимущество, что он также может работать с именами файлов, содержащими пробелы, табуляции, символы новой строки и символы подстановки имени файла (имена файлов никогда не помещайте в одну строку, которую мы затем пытаемся перебрать ).

В оболочке bashвы можете сделать то же самое с [[... ]]тестом сопоставления с образцом, как вы пытались сделать сами:

#!/bin/bash

cd Folder || exit 1

shopt -s nullglob

for name in *b*; do
    [[ $name != *a* ]] && printf '%s\n' "$name"
done

См. также:

5
18.03.2021, 22:41

Чтобы напечатать имена файлов в Folder, которые содержат b, а не a, в zshи его ~(, за исключением /и -, а не)оператор glob:

#! /bin/zsh -
set -o extendedglob
print -rC1 -- Folder/(*b*~*a*)(N:t)

(удалитеN(для nullglob, если вы хотите, чтобы сообщалось об ошибке, когда нет соответствующего файла ).

Вksh93(оболочке, которая представила этот [[...]]оператор (, который не является частью стандартного shсинтаксиса ), а его&(и!(...)(не)операторы:

#! /bin/ksh93 -
(
  CDPATH= cd Folder &&
    set -- ~(N)@(*b*&!(*a*)) &&
    (($# > 0)) &&
    printf '%s\n' "$@"
)

В оболочке bash(, которая, как и zsh, также скопировала оператор [[...]]ksh ), используя extglobдля поддержки операторов glob ksh88 и nullglobдля получения эффекта от Nzsh. ] квалификатор glob или ksh93оператор glob ~(N)и некоторое двойное отрицание с|(или)для достижения и:

#! /bin/bash -
(
  shopt -s extglob nullglob
  cd./Folder &&
    set -- !(!(*b*)|*a*) &&
    (($# > 0)) &&
    printf '%s\n' "$@"
)

В стандартном синтаксисе sh:

#! /bin/sh -
(
  CDPATH= cd Folder || exit
  set -- [*]b[*] *b*
  [ "$1/$2" = '[*]b[*]/*b*' ] && exit # detect the case where the pattern
                                      # expands to itself because there's
                                      # no match as there's no nullglob
                                      # equivalent in sh
  shift
  for i do
    case $i in
      (*a*) ;;
      (*) set -- "$@" "$i"
    esac
    shift
  done
  [ "$#" -gt 0 ] && printf '%s\n' "$@"
)

Обратите внимание, что решения, использующие cd, не будут работать, если у вас есть доступ для чтения к Folder, но нет доступа к нему для поиска.

В более общем смысле, чтобы ответить на общий вопрос о том, как проверить, содержит ли строка другую строку в sh, лучше всего использовать конструкцию case, которая используется для сопоставления с образцом в sh. Вы даже можете использовать вспомогательную функцию:

contains()
  case "$1" in
    (*"$2"*) true;;
    (*) false;;
  esac

Использовать как если бы:

if contains foobar o; then
  echo foobar contains o
fi
if ! contains foobar z; then
  echo foobar does not contain o
fi
if
  contains "$file" b &&
    ! contains "$file" a
then
  printf '%s\n' "$file contains b and not a "
fi
6
18.03.2021, 22:41

Теги

Похожие вопросы