@steeldriver уже объяснил, что \b
относится к , я просто добавлю, что apt-file search
сам по себе поддерживает расширенное регулярное выражение с опцией -x
, и что вы можете искать пути , заканчивающиеся в apache2.conf
с:
apt-file search -x 'apache2\.conf$'
Вы также можете:
apt-file search -x 'apache2\.conf(\s|$)'
Искать пути, которые заканчиваются на apache2.conf
или содержат apache2.conf
, за которым следует пробел, но я сомневаюсь, что это будет иметь какое-либо значение, поскольку я не ожидаю, что какой-либо файл в базе данных apt-file
содержит apache2.conf
.
Выход из подоболочки не приведет к выходу из основного сценария, как вы это видели.
Я думаю о 3 (с половиной )решениях:
set -e
, чтобы любая ("непроверенная" )неудачная команда (или подоболочка )немедленно выходили из основного сценария (это может быть излишним или вызывать другие проблемы ), trap
|| exit $?
после каждого VALUEn=$(...)
вот так VALUE=$(require_line "myKey") || exit $?
, eval
. Этот третий не совсем «требует if вокруг каждого» и все равно будет довольно компактным синтаксисом IMHO.
Кстати , эта строчка
echo "Key not found in $DATA, key: $KEY"
...на самом деле бесполезно, если вы выйдете из всего скрипта сразу после этого, потому что предложение будет сохранено в переменной $VALUEn
, которая не будет отображаться.
Предлагаю печатать на stderr
вот так:
echo "my error" 1>&2
#!/bin/sh
set -e
myfunc(){
echo $1
if [ "$1" != "OK" ] ; then exit 1 ; fi
}
VALUE1=$(myfunc "OK")
echo $VALUE1
VALUE2=$(myfunc "NO WAY")
echo $VALUE2
echo "main script did not exit"
$./test.sh
OK
zsh: exit 1 ./test.sh
Но если я уберу set -e
с самого начала, я получу:
$./test.sh
OK
NO WAY
main script did not exit
#!/bin/sh
trap "exit $?" USR1
myfunc(){
echo $1
if [ "$1" != "OK" ] ; then kill -USR1 $$ ; fi
}
VALUE1=$(myfunc "OK")
echo $VALUE1
VALUE2=$(myfunc "NO WAY")
echo $VALUE2
echo "main script did not exit"
$./test.sh
OK
#!/bin/sh
myfunc(){
echo $1
if [ "$1" != "OK" ] ; then exit 1 ; fi
}
VALUE1=$(myfunc "OK") || exit $?
echo $VALUE1
VALUE2=$(myfunc "NO WAY") || exit $?
echo $VALUE2
echo "main script did not exit"
$./test.sh
OK
zsh: exit 1 ./test.sh
#!/bin/sh
myfunc(){
echo $1
if [ "$1" != "OK" ] ; then exit 1 ; fi
}
I=1
for key in "OK" "OK" "NO WAY": ; do
eval "VALUE$I=\$(myfunc \"$key\")" || exit $?
eval "echo \$VALUE$I"
I=$(($I+1))
done
echo "main script did not exit"
$./test.sh
OK
OK
zsh: exit 1 ./test.sh
Давайте немного изменим структуру вашего require_line
скрипта, чтобы помочь вам.
Во-первых, мы можем избавиться от бесполезного cat | grep
. Во-вторых, мы можем использовать grep
внутреннее поведение, указывающее на успех или неудачу поиска KEY
, а также печать ключа, если он найден, в stdout
.
require_line(){
local KEY="$1"
local FILE="/tmp/myfile"
if grep "$KEY" "$FILE"
then
return 0
else
printf 'Key not found in:\n\n"%s"\n\nKey: "%s"\n' "$(cat "$FILE")" "$KEY" >&2
return 1
fi
}
Это использует встроенный -в поведение grep
. Если ключ найден, grep
печатает соответствующую строку и возвращает успех. В противном случае берется ветвь else
и выводится сообщение о том, что ключ не найден. Кроме того, в случае сбоя grep
сообщение об ошибке печатается в stderr
, чтобы сообщение об ошибке не было ошибочно принято за действительное совпадение найдено в $FILE
.
Вы можете дополнительно изменить require_line
, чтобы принять имя файла в качестве $2
параметр, изменив строку на local FILE="$2"
и затем передав нужное имя файла каждый раз, когда вы вызываете require_line
.
Теперь, когда это на месте....
Вам действительно нужно хранить каждое VALUEn для KEYn, или вам просто нужно убедиться, что они все присутствуют?
Теперь, когда у вас есть функция require_line
, которая точно возвращает успех или значение ошибки, вы можете просто AND
все ваши тесты вместе. Как только любой из них не пройден, общий тест не пройден.
Предполагая, что вам действительно нужны фактические значения соответствия, длинный -извилистый способ сделать это будет:
if value1=$(require_line "key1") &&
value2=$(require_line "key2") &&
value3=$(require_line "key3")
then
printf "%s\n" "$value1" "$value2" "$value3"
else
printf "One or more keys failed.\n" >&2
fi
Это будет утомительно, если у вас есть множество ключей для проверки. Использование массива может быть лучше:
#!/usr/bin/env bash
require_line(){
local KEY="$1"
local FILE="/tmp/myfile" # or perhaps "$2"
if grep "$KEY" "$FILE"
then
return 0
else
printf 'Key not found in:\n\n"%s"\n\nKey: "%s"\n' "$(cat "$FILE")" "$KEY" >&2
return 1
fi
}
declare keys=("this" "is" "a" "test" "\." "keyN")
N=${#keys[@]}
declare values=()
j=0
while [ $j -lt $N ] && values[$j]="$(require_line "${keys[j]}")"
do
j=$(($j+1))
done
if [ $j -lt $N ]
then
printf 'error: found only %d keys out of %d:\n' $j $N
printf ' "%s"\n' "${values[@]}"
fi
Запуск этого кода с некоторыми демонстрационными данными:
$ cat /tmp/myfile
this is a test.
$./test.sh
Key not found in:
"this is a test."
Key: "keyN"
error: found only 5 keys out of 6:
"this is a test."
"this is a test."
"this is a test."
"this is a test."
"this is a test."
""
Наконец, если вам действительно нужно только убедиться, что все ключи присутствуют, без необходимости знать, каковы значения совпадения, код, ориентированный на массив -выше, может быть упрощен до простого цикла до тех пор, пока не будут найдены все ключи, или для прервать при первой обнаруженной отсутствующей клавише.