터미널에서 다음 명령을 실행합니다.
grep "bla bla blah" blah* | echo "Blah: $(wc -l) / $(ls | wc -l) * 100"
나는 다음과 같은 결과를 얻습니다.
Blah: 44 / 89 * 100
내가 보기를 기대하는 것:
49.4
bash 명령만 사용하여 원하는 출력을 얻을 수 있는 방법이 있습니까? 파이프하려는 스크립트의 출력이 마음에 들지 않습니다.
답변1
귀하의 코드는 문자열을 인쇄한다고 말합니다. 문자열이 실제로 평가하려는 산술 표현식이라는 것을 나타내는 곳은 없습니다. 따라서 귀하의 표현이 평가될 것이라고 합리적으로 기대할 수 없습니다.
귀하의 코드가 최적이 아닙니다. $(wc -l)
반환된 일치 항목 수를 계산 grep
하지만 더 쉬운 방법이 있습니다. grep -c
대신 실행하세요. $(ls | wc -l)
현재 디렉토리에서 점이 아닌 파일을 계산하는 신뢰할 수 없는 방법입니다.출력이 ls
신뢰할 수 없습니다.; $(set -- *; echo $#)
는 이를 수행하는 신뢰할 수 있는 방법입니다(적어도 하나의 일치하는 파일이 있다고 가정하고 해당 가정이 유지되지 않을 수 있는 경우 사용하십시오. $(set -- *; if [ -e "$1" ]; then echo $#; else echo 0; fi
그러나 이로 인해 0으로 나뉘게 되며 그 이하에서는 어떻게든 오류 조건으로 처리되어야 합니다). 따라서 다음과 같이 코드를 작성할 수 있습니다.
matches=$(grep -c "bla bla blah" blah*)
files=$(set -- *; echo $#)
echo "Blah: $matches / $files * 100"
또는 두 중간 값의 계산을 인라인으로 수행할 수 있습니다.
echo "Blah: $(grep -c "bla bla blah" blah*) / $(set -- *; echo $#) * 100"
이제 산술 연산을 수행하기 위해 쉘의 내장 함수를 사용할 수 있습니다.산술 확장, 그러나 정수 연산으로 제한되므로 /
연산자는 가장 가까운 정수로 반올림합니다.
echo "Blah: $(($matches * 100 / $files))"
ksh93, zsh 및 yash(다른 쉘에서는 제외)에서 표현식에 부동 소수점을 강제하는 항목(예: 부동 소수점 상수)이 있으면 부동 소수점 산술을 얻게 됩니다. 이 기능은 Bourne Shell, ksh88, pdksh, bash, ash에는 존재하지 않습니다.
echo "Blah: $(($matches * 100.0 / $files))"
이것bc
유틸리티는 임의의 정밀도로 십진수에 대한 연산을 수행합니다.
echo "Blah: $(echo "scale=2; $matches * 100 / $files" | bc)"
부동 소수점 계산을 수행할 수 있는 또 다른 표준 유틸리티(사용 가능한 수학 함수 수가 적음)는 다음과 같습니다.awk
.
echo "$matches" "$files" | awk '{print "Blah:", $1 * 100 / $2}'
답변2
첫째, 쉘을 지정하지 않았습니다. 를 사용하고 있다고 가정하겠습니다 bash
. 나중에 설명해주세요.
또한 매우 중요한 것은 당신입니다아니요구문 분석된 출력 ls
. 이 작업을 수행하지 않는 이유에 대한 좋은 문서가 있습니다.여기.
반품,무엇백분율 출력을 얻으려고합니까? 마지막에 백분율을 계산하려고하지 않는 것 같습니다. 이제 나는 당신이 나열한 정확한 계산을 수행했습니다.
언급된 문제 없이 이 작업을 수행할 수 있는 작은 스크립트는 다음과 같습니다.
#!/bin/bash
_die() {
printf '%s\n' "${@:2}"
exit "$1"
}
(( $# )) || _die 1 "Usage: ${0##*/} pattern <dir>"
[[ $2 ]] && _dir=$2 || _dir=.
[[ -d ${_dir} ]] || _die 2 "Directory does not exist: ${_dir}"
for _file in "${_dir}"/*; do
[[ -f ${_file} ]] && _files+=( "${_file}" )
done
(( ${#_files[@]} )) || _die 3 'No files matched by glob, not attempting to divide by 0.'
# We pass the same files found to grep instead of reglobbing to avoid a race condition.
while IFS= read -r _number_of_matches; do
(( _total_matches )) && (( _total_matches+=_number_of_matches )) || _total_matches=${_number_of_matches}
done < <(grep -hc "$1" "${_files[@]}")
(( _total_matches )) || _die 4 "Nothing matched by expression: $1"
printf 'Blah: %s\n' "$(bc <<< "${_total_matches}/${#_files[@]}")"
bc
휴대가 불가능 하니 참고하세요 . 정수 연산을 사용해도 괜찮다면 를 bc
사용 하는 대신 셸을 사용하여 계산하고 반환할 수 있습니다 $((
.
답변3
이 같은?
echo "scale=2;100*`grep 'bla bla bla' bla* | wc -l`/`cat bla* | wc -l`" | bc