sed
다음과 같이 (null이 아닌 것으로 알려진 ) 외부 유틸리티를 호출하여 $myvar
이 작업을 수행 할 수 있습니다.
if [ "$(printf %s "$myvar" | sed -n '$=')" -eq 1 ]; then
echo "Your variable has only one line, proceeding"
else
echo "Error condition, variable must have only one line"
fi
bash
내장된 함수만 사용하여 이를 수행할 수 있는 방법이 있습니까 ?
더 좋은 점은 외부 유틸리티를 호출하지 않고 POSIX 지정 방식으로 이 작업을 수행할 수 있는 방법이 있습니까?
(이 질문은 호기심과 더 나은 작업 방법을 찾는 것 중 하나입니다. 위의 코드는하다기능. 더 깨끗하고 빠른 방법이 있는지 궁금합니다. )
답변1
POSIX 방식:
NL='
'
case $myvar in
*"$NL"*) echo more than one line ;;
*) echo one line ;;
esac
이는 POSIX 이전 Bourne 유사 쉘에도 적용됩니다.
답변2
여러 가지 옵션이 있습니다(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 값으로 종료되고, 변수 $a
에 개행 문자가 여러 개 있는 경우(multiple ) $'\n'
1 의 값으로 종료됩니다.
함수를 실행하면 필요한 줄이 인쇄됩니다.
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에서 실패합니다.
=~
areregex: POSIX에는 정규식 연산자가 없습니다.==
apattern: POSIX에는 연산자가 없습니다.- areplace: 매개변수 확장에는 옵션이 없습니다
${ / / }
.
그 중 4개는 POSIX로 안전하게 변환될 수 있습니다.
- posixcut: 아마도 가장 좋은 솔루션일 것입니다.
- posixcase : POSIX 쉘을 위한 일반적인 솔루션입니다.
- posixifs: setup을 활성화하기 위해 서브셸 내에서 실행됩니다
set -f
. -d
posixread: 읽기에는 또는 가 없지만-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는 아니지만좋은 지원을 받다.
Local 은 b
안전하게 제거할 수 있습니다(전역 $b
사용량 확인).
본 슈프리머시(1977 Shell).
1977년의 원래 Bourne 셸에 대한 코드가 필요한 경우 다음 코드를 사용하세요.
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 ]; }
posixcut에서 사용되는 확장은 ${a%% }
Bourne에서 작동하지 않습니다. Bourne에서 작동하려면 posixif를 두 부분으로 나누어야 합니다.
읽기 옵션에는 상당한 변경이 필요하지만 정상적으로 작동합니다.
해당 기능은 posixread이고 bourneread는 필수 보조 기능입니다.
Bourne의 모든 코드는 작동 테스트를 거쳤습니다.가보 껍질.
답변3
다음 코드 조각은 작동합니다 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
답변4
다음과 같이 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"