문자열에 문자(특정 문자가 아니라 실제로는 모든 문자)가 두 번 이상 포함되어 있는지 확인하고 싶습니다.
예를 들어:
사용자:
test.sh this list
스크립트:
if [ "$1" has some letter more then once ]
then
do something
fi
답변1
당신은 그것을 사용할 수 있습니다 grep
.
정규식은 \(.\).*\1
임의의 단일 문자, 그 뒤에 임의의 문자, 그 뒤에 동일한 첫 번째 문자가 오는 것과 일치합니다.
grep
하나 이상의 줄이 정규식과 일치하면 성공을 반환합니다.
if echo "$1" | grep -q '\(.\).*\1' ; then
echo "match" ;
fi
문자가 아닌 모든 문자와 일치 하려면 \(.\)
정규식을 "의 특정 정의로 제한해야 할 수도 있습니다.정말 어떤 편지라도" . 또는 같은 것을 사용할 수 있습니다 \([[:alnum:]]\).*\1
.\([[:alpha:]]\).*\1
\([a-df-z1245]\).*\1
답변2
fold
한 줄에 한 문자를 인쇄하는 문자열을 사용한 다음 uniq -c
그 수를 세어 awk
두 번 이상 나타나는 문자만 인쇄할 수 있습니다.
$ string="foobar"
$ fold -w 1 <<< "$string" | sort | uniq -c | awk '$1>1'
2 o
또는 쉘이 이 문자열을 지원하지 않는 경우:
printf '%s\n' "$string" | fold -w 1 | sort | uniq -c | awk '$1>1'
그런 다음 위 명령이 빈 문자열을 반환하는지 테스트할 수 있습니다.
$ string="foobar"
$ [ -n "$(fold -w 1 <<<"$string" | sort | uniq -c | awk '$1>1')" ] && echo repeated
repeated
그런 다음 이를 쉽게 확장하여 반복되는 문자와 반복 횟수를 인쇄할 수 있습니다.
$ rep="$(fold -w 1 <<<"$string" | sort | uniq -c | awk '$1>1')"
$ [ -n "$rep" ] && printf -- "%s\n" "$rep"
2 o
답변3
c=$(expr " $string" : " .*\(.\).*\1") || [ "$c" = 0 ] &&
printf '"%s" has "%s" (at least) more than once\n' "$string" "${c:-<newline>}"
(0은 expr
false를 반환하며 개행 명령 대체 막대는 특별히 처리되어야 합니다).
중복 보고서 받기바이트, GNU 시스템에서는 다음을 수행할 수 있습니다.
$ string=$'This is a string\nwith «multi-byte» «characters»\n'
printf %s "$string" | od -An -vtc -w1 | LC_ALL=C sort | LC_ALL=C uniq -dc
5
3 a
2 c
2 e
3 h
5 i
3 r
4 s
5 t
2 \n
2 253
2 273
4 302
ASCII 범위 밖의 바이트는 8진수 값으로 표시되고 제어 문자는 \x
8진수 값 또는 C 표현으로 표시됩니다.
중복 보고서 받기수치:
$ printf %s "$string" | recode ..dump | sort | uniq -dc
2 000A LF line feed (lf)
5 0020 SP space
3 0061 a latin small letter a
2 0063 c latin small letter c
2 0065 e latin small letter e
3 0068 h latin small letter h
5 0069 i latin small letter i
3 0072 r latin small letter r
4 0073 s latin small letter s
5 0074 t latin small letter t
2 00AB << left-pointing double angle quotation mark
2 00BB >> right-pointing double angle quotation mark
그러나 recode
모든 유니코드 문자(특히 최근 문자)를 알 수는 없습니다.
쉘 내장 함수를 사용하십시오.
ksh93에서:
if [[ $string = *@(?)*\1* ]]; then
print -r -- "$string contains duplicate characters"
fi
zsh에서:
set -o rematchpcre
if [[ $string =~ '(.).*\1' ]]; then
print -r -- "$string contains duplicate characters ($match[1] at least)"
fi
( set -o rematchpcre
표준 확장으로 역참조를 지원하는 ERE가 없는 시스템에서도 작동합니다.)
또는 반복되는 모든 문자 목록을 얻으십시오.
typeset -A count=()
for c (${(s[])string}) if (( ++count[\$c] == 2 )) print -r -- $c is found more than once
답변4
이 질문은 8년 전에 제기된 질문이지만 이전의 모든 답변에는 외부 도구가 필요하고 여러 서브셸이 필요한 긴 파이프 표현이 필요하다는 점을 고려하여 bash라는 태그가 지정된 질문에도 불구하고 내부 솔루션을 제안하고 싶었습니다.
이 함수는 count_chars()
동일한 이름의 PHP 함수와 유사하게 작동합니다. 문자열을 입력으로 받아들이고 각 문자에 대해 연관 배열에 나타나는 횟수를 기록합니다. 결과를 보유하는 배열은 참조에 의해 첫 번째 인수로 전달됩니다.
그러면 인덱스(키)를 반복하여 필터 조건을 충족하는 모든 문자를 쉽게 얻을 수 있습니다.
편집: 업데이트된 코드는 Bash 4.3 이상에서 작동합니다.
#!/bin/bash
# Count character occurences in string $2. For each contained character, return
# the number of occurrences in the associative array $1.
# This is similar to the PHP function count_chars(), mode 1.
count_chars() {
[ "$1" = "arr" ] || { declare -n arr 2>/dev/null || return 1; arr="$1"; }
arr=( )
local -i i
local ch
for (( i=0; i<${#2}; i++ )); do
ch=${2:$i:1}
# http://mywiki.wooledge.org/BashPitfalls#A.5B.5B_-v_hash.5B.24key.5D_.5D.5D
[[ -v 'arr["$ch"]' ]] || arr["$ch"]="0"
# Surprise, surpise--the increment works, despite
# http://mywiki.wooledge.org/BashPitfalls#A.28.28_hash.5B.24key.5D.2B-.2B-_.29.29
# (( ++arr["$ch"] )) EDIT: Bash 5.2+ only
let '++arr["$ch"]'
done
}
declare -A A=
count_chars A "Die Hoffnung stirbt zuletzt!"
for k in "${!A[@]}"; do
(( ${A[$k]} > 1 )) && printf '%s|' "$k"
done
echo
스크립트는 다음을 인쇄합니다.
|z|u|t|n|i|f|e|
첫 번째 결과 문자는 비어 있습니다. 이것이 올바른지 쉽게 확인할 수 있습니다.
$ declare -p A
declare -A A=(["!"]="1" [" "]="3" [H]="1" [D]="1" [z]="2" [u]="2" [t]="4" [s]="1" [r]="1" [o]="1" [n]="2" [l]="1" [i]="2" [g]="1" [f]="2" [e]="2" [b]="1" )
배열 처리를 계속하려면 배열에서 일치하지 않는 요소를 제거하면 됩니다.
for k in "${!A[@]}"; do
(( ${A[$k]} > 1 )) || unset -v 'A[$k]'
done
declare -p A
결과:
declare -A A=([" "]="3" [z]="2" [u]="2" [t]="4" [n]="2" [i]="2" [f]="2" [e]="2" )