문자열에 공백과 해시 문자("#")만 포함되어 있는지 확인하는 이 코드가 있습니다. 그렇다면 "예"를 에코하고 그렇지 않으면 "아니오"를 에코합니다.
string="###############
# #
# #############
# #
# ######### # #
# # # #
# ### ##### # #
# # # # #
# # ###########
# #
###############"
confirm_variable="Yes"
for (( i=0; i<${#string}; i++ )); do
str="${string:$i:1}"
if [ "$str" == "#" ] || [ "$str" == " " ] || [ "$str" == "\n" ] ;
then
continue
else
confirm_variable="No"
break
fi
done
echo $confirm_variable
왜 이것이 작동하지 않는지 잘 모르겠습니다. 문자열을 다음과 같게 만드는 것과 같습니다.
string="## #### # # #"
아주 잘 작동하는 것 같습니다.
답변1
"\n"
두 문자 백슬래시와 소문자 n입니다.
이제 일부 쉘에서는 echo "\n"
개행 문자(실제로는 2개)를 인쇄하고 모든 쉘에서는 을 인쇄합니다 printf "\n"
. 하지만 이는 백슬래시가 특별히 취급되기 때문입니다 echo
. printf
이는 백슬래시 이스케이프가 항상 (큰따옴표로 묶인) 문자열에서 특별히 처리되는 C, Perl 및 Python과 같은 언어와 다릅니다.
많은 쉘에서 $'\n'
이것은 개행 문자만 포함하는 문자열일 것입니다. (그러나 순수 POSIX sh에서는 따옴표 안에 리터럴 개행 문자를 추가해야 합니다.)
즉, Bash/Ksh/Zsh에서는 수동으로 반복하는 대신 정규식에 대해 문자열을 테스트할 수 있습니다.
re=$'^[# \n]*$'
if [[ $string =~ $re ]]; then
echo "string contains only #, space and newline"
fi
( for (( .. ))
또한 ${string:i:j}
이는 표준 POSIX 기능이 아니며 Ubuntu에 있는 Dash 등에서는 작동하지 않습니다 /bin/sh
.)
답변2
다른 사람들이 지적했듯이 "\n"
개행 문자가 아니라 \
a 및 문자열이 있습니다 n
.
문자열에 공백, 해시 및 줄바꿈만 포함되어 있는지 검색하려면 각 개별 문자를 반복하는 대신 패턴 일치를 사용하세요.
다음을 수행할 수 있습니다.
case $string in
(*[![:space:]#]*)
echo 'other characters in string'
;;
(*)
echo 'only space-like characters or hashes in string'
esac
또는 다음과 같습니다( bash
).
if [[ $string == *[![:space:]#]* ]]; then
echo 'other characters in string'
else
echo 'only space-like characters or hashes in string'
fi
여기서 사용하는 것은 [:space:]
공백, 탭(다양한 유형), 캐리지 리턴 및 줄 바꿈을 포함하여 다양한 공백 유사 문자와 일치하는 POSIX 문자 클래스입니다. 이 패턴은 *[![:space:]#]*
다음 문자를 포함하는 모든 문자열과 일치합니다.아니요공백 같은 문자 또는 #
.
탭이나 캐리지 리턴을 허용하지 않는 등 좀 더 제한적으로 적용하려면 $'*[! \n#]*'
다음 패턴을 사용하세요 bash
.
pattern=$'*[! \n#]*'
if [[ $string == $pattern ]]; then
echo 'other characters in string'
else
echo 'only spaces, hashes, or newlines in string'
fi
또는 표준 sh
셸에서 다음을 수행합니다.
pattern='*[!
#]*'
case $string in
($pattern)
echo 'other characters in string'
;;
(*)
echo 'only spaces, hashes, or newlines in string'
esac
답변3
가장 사소한 문자열이나 텍스트 조작 이외의 작업을 수행하기 위해 sh(일반 sh에서 bash, ksh 또는 zsh까지의 모든 변형)를 사용해서는 안 됩니다. 바라보다쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?몇 가지 이유.
여러 줄 문자열의 각 문자에 대한 반복은 셸에서 개별적으로 수행되어서는 안 됩니다. 속도가 매우 느리고 모든 종류의 인용 및 줄 끝 표시(예: \n
)에 문제가 있으며 대부분의 sh 버전(bash, ksh 및 zsh 제외)에는 내장 기능도 없습니다. 정규식 지원 - 제 생각에는 이것이 텍스트 처리에 필요한 최소한의 기능입니다.
대신 다른 텍스트 처리 유틸리티/언어를 awk
사용 하십시오.perl
예를 들어 전체 for 루프를 다음으로 바꿀 수 있습니다.
echo "$string" | perl -lne 'BEGIN {$c="Yes"; $ec=0};
if (!m/^[ #]+$/) { $c="No"; $ec=1; last };
END {print $c; exit $ec}'
또는
echo "$string" | awk -v c="Yes" -v ec=0 \
'!/^[ #]*$/ { c="No"; ec=1; nextfile };
END { print c; exit ec}'
이를 위해서는 GNU awk (또는 기타 지원되는 awk nextfile
)가 필요합니다. 다른 버전의 awk에서는 다음 코드가 작동하지만 일치 오류 시 루프를 즉시 종료하지 않기 때문에 약간 느립니다.
echo "$string" | awk -v c="Yes" -v ec=0 \
'!/^[ #]*$/ { c="No"; ec=1 };
END { print c; exit ec}'
분명히 이들은 동일한 스크립트이며 다른 Perl 및 awk 구문에 대해 약간 다르게 다시 작성되었습니다.
위의 정규식은 perl과 awk 모두에서 사용됩니다 /^[ #]*$/
. !
이는 공백이나 해시만 포함하지 않는 모든 줄과 일치합니다.
세 가지 모두 올바른 입력이 확인되면 종료 코드 0을 반환하고 일치하는 항목이 없으면 1을 반환합니다. 이는 sh 의 변수를 사용하여 $?
테스트 할 수 있습니다.
if [ $? -eq 1 ] ; then
: # string has bad characters, do something!
fi
간단한 GNU 스크립트를 사용할 수도 있습니다 sed
.
echo "$string" | sed -n -e '/[^ #]/q1'
if [ $? -eq 0 ] ; then echo "Yes" else echo "No" ; fi
(quit) 명령의 종료 코드 q
는 sed의 GNU 확장이므로 GNU sed가 필요합니다.
또는 @Isaac이 지적했듯이 grep
's -q
(또는 --quiet
/ --silent
) 옵션을 사용할 수 있습니다. 그러면 일반 출력이 억제되고 종료 코드만 반환됩니다. 예를 들어:
echo "$string" | grep -q '[^ #]'
if [ $? -eq 0 ] ; then echo "Yes" else echo "No" ; fi