Проверить, есть ли в переменной оболочки более одной строка с использованием встроенных модулей?

С помощью gnu sed:

sed -Es '/pattern1|pattern2|pattern3/{
s/.*:[[:blank:]]*//;H}
$!d;x;/^\n$/d;s/\n(.*)/\1,/;s/\n/,/g' folder/*.txt > list.txt

где list.txt содержимое будет примерно таким:

file1match1,file1match2,
file2match1,
file4match1,file4match2,file4match3,

так file3 отсутствует в выводе, поскольку не было строки, соответствующей pattern*.
Как это работает: обрабатывает каждый файл -sотдельно, удаляя (через s/.*:[[:blank:]]*//) ненужную часть в строках, соответствующих pattern* и добавляя результат в Hold буфер. Он удаляет каждую строку, кроме la$t, когда он exменяет буферы. Если в пространстве шаблона есть только \newline, это означает, что ни одна строка в этом файле не соответствует pattern*, поэтому он удаляет пространство шаблона. Иначе он удаляет ведущую \nстроку, заменяет оставшиеся запятыми и добавляет последующую запятую.

С другими sedами вам придется выполнить цикл:

for file in folder/*.txt do
sed '/pattern1\|pattern2\|pattern3/{
s/.*:[[:blank:]]*//
H
}
$!d
x
/^\n$/d
s/\n\(.*\)/\1,/
s/\n/,/g' "$file"
done > list.txt
3
20.04.2016, 05:14
5 ответов

Есть несколько вариантов (сначала bash, ниже POSIX).
Код внутри каждой функции можно легко использовать снаружи.

#!/bin/bash

nl=$'\n'

aregex   (){ [[ $a =~        $nl     ]]; }
apattern (){ [[ $a ==       *$nl*    ]]; }
acut     (){ [[ $a != "${a%%"$nl"*}" ]]; }
areplace (){ [[ $a != "${a//"$nl"/}" ]]; }
acase    (){ case $a in (*$nl*) true;; (*) false;; esac; }
aifs     ()( IFS="$nl"
             set -f; set -- x${a}x;
             (( $# > 1 ));
           )
aread    (){ IFS="$nl" read -rd '' -a b <<<"x${a}x";
             (( "${#b[@]}" > 1 )); }

Каждая функция - это опция. Каждая функция завершается с возвращаемым значением 0, если есть только одна строка, и возвращаемым значением 1, если переменная $ a имеет более одной новой строки (более одной $ '\ n ').

После выполнения функции будет напечатана требуемая строка:

out=''; "$function" && out="more than "
printf "%9s   = %sone line\n" "$1" "$out"

Выполнение всех параметров:

a='ab'"$nl"'cd' ; alltests
a='ab  cd'      ; alltests

Выдает следующий результат:

   aregex   = more than one line
 apattern   = more than one line
     acut   = more than one line
 areplace   = more than one line
    acase   = more than one line
     aifs   = more than one line
    aread   = more than one line

   aregex   = one line
 apattern   = one line
     acut   = one line
 areplace   = one line
    acase   = one line
     aifs   = one line
    aread   = one line  

POSIX

Следующие параметры не работают в POSIX по нескольким причинам:

  • aregex: в POSIX нет операторов регулярных выражений = ~ .
  • apattern: В POSIX нет оператора == .
  • areplace: в раскрытии параметров отсутствует параметр $ {/ /} .

Четыре можно безопасно перевести в POSIX:

  • posixcut: Вероятно, лучшее решение.
  • posixcase: распространенное решение для оболочек POSIX.
  • posixifs: выполняется внутри суб-оболочки, чтобы иметь возможность установить set -f .
  • posixread: read не имеет -d или -a , но его можно адаптировать.

#!/bin/dash

nl='
'

posixcut (){ [ "${a}" != "${a%%"$nl"*}" ] ; }
posixcase(){ case $a in (*$nl*) true;; (*) false;; esac; }
posixifs ()( IFS="$nl";
             set -f; set -- x${a}x;
             [ "$#" -gt 1 ];
           )
posixread(){ local b=0;
             while IFS=$nl read -r _; do
                 b=$((b+1));
                 [ $b -gt 1 ] && break;
             done <<-_EOT_
x${a}x
_EOT_
             [ $b -gt 1 ];
           }

Примечание : Да, local не является строго POSIX, но довольно хорошо поддерживается .
Локальный объект для b можно безопасно удалить (проверьте глобальное использование $ b ).

Борн (оболочка 1977 г.).

Если вам нужен код для исходной оболочки Bourne 1977 года, используйте это:

posixcase() { case $a in *$nl*) true;; *) false;; esac; }
posixifs () ( IFS="$nl"
              set -f; set -- x${a}x;
              [ "$#" -gt 1 ];
            )
bourneread()( b=0                ### A helper function.
              while :; do
                  if IFS=$nl read c && [ $b -le 1 ]; then
                      b=`expr $b + 1`
                  else
                      echo "$b"
                      break
                  fi    
              done <<-_EOT_
x${a}x
_EOT_
             )
posixread   (){ [ `bourneread` -gt 1 ]; }

Расширение $ {a %%} , используемое в posixcut, не будет работать в Bourne. Posixifs Чтобы работать в Борне, его нужно разделить на две части.
Параметр чтения требует изменений мэра, но работает правильно.
Его функция - posixread, bourneread - обязательная вспомогательная функция.

Весь код Bourne был протестирован на предмет правильной работы с семейной оболочкой .

5
27.01.2020, 21:07

Вот способ, который должен работать со всем синтаксисом Борна / оболочками POSIX и использует только встроенные функции:

if (set -f ; IFS=$'\n'; set -- x${myvar}x ; [ $# = 1 ]) ; then
  echo "Your variable has only one line, proceeding"
else
  echo "Error condition, variable must have exactly one line"
fi

Если ваша оболочка не поддерживает IFS = $ '\ n' (например, тире 0.5.7), вы можете вместо этого использовать:

IFS="
"
1
27.01.2020, 21:07

Способ POSIX:

NL='
'
case $myvar in
  *"$NL"*) echo more than one line ;;
        *) echo one line ;;
esac

Это также работает в оболочках, подобных Bourne до POSIX.

10
27.01.2020, 21:07

Следующие фрагменты работают в bash (с параметром -posix и без него):

#!/bin/bash
#!/bin/bash -posix
version_1 () { [[ "$myvar" = *$'\n'* ]]; }
version_2 () {
  local newlines="${myvar//[^$'\n']/}"
  [[ "${#newlines}" -eq 1 ]]
}
for test in version_1 version_2; do
  if $test; then echo many lines; else echo one line; fi
done
6
27.01.2020, 21:07

Я бы рекомендовал использовать расширение параметра Bash следующим образом:

n="${myvar//[^\n]}"; if [ ${#n} -eq 1 ]; then
  echo "Your variable has only one line, proceeding"
else
  echo "Error condition, variable must have only one line"
fi

Тестовые образцы:

myvar="xxx"
myvar="xx\nxx"
myvar="xx\nx\nx"
1
27.01.2020, 21:07

Теги

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