표준 입력에서 나오는 "<" 및 ">"와 같은 기호를 계산하려면 bash 스크립트를 작성해야 합니다.
예를 들어:
$ ./myscript.sh <example.html
> - 20
< - 21
Found mismatching brackets!
나는 이걸했다:
x=`grep -o '>' example.html | wc -l`
y=`grep -o '<' example.html | wc -l`
if [ "$x" -ne "$y" ]; then
echo "Mismatch!"
fi
echo $x
echo $y
이것이 좋은 접근 방식입니까? 표준 입력에서 "example.html" 파일 이름을 얻는 방법을 모르겠습니다.
답변1
요점은 stdin
무엇이든 될 수 있다는 것입니다. 예를 들어 파이프, 네트워크 소켓, 일반 파일, 장치가 될 수 있으며 스크립트가 시작되면 일반 파일의 절반이 될 수 있습니다... 가능하다면 데이터를 한 번 처리할 수 없으면 다음으로 제한됩니다.탐색 가능한파일, 즉 일반 파일 및 일부 장치 파일 또는 정보는 어떻게든 저장되어야 합니다(임시 파일 또는 메모리...). 그러나 모든 정보는 여기에서 즉시 확인할 수 있습니다.
예를 들어 다음과 같이 할 수 있습니다.
$ grep -o '[<>]' < a.html | sort | uniq -c
82 <
82 >
POSIX적으로:
fold -w 1 a.html | grep '[<>]' | sort | uniq -c
불일치를 감지하려면 다음을 수행하십시오.
if fold -w 1 a.html | awk '{n[$0]++}
END{exit(n["<"]!=n[">"])}'
then
echo match
else
echo mismatch
fi
이제 이 주제의 질문에 답하기 위해 Linux에서는 다음을 사용하여 stdin의 "이름"을 찾을 수 있습니다.
readlink -f /dev/stdin
예:
$ readlink -f /dev/stdin < a
/home/chazelas/a
$ : | readlink -f /dev/stdin
/proc/20238/fd/pipe:[758683]
(위의 20238은 pid이므로 readlink
종료 후에는 경로가 많이 사용되지 않습니다 readlink
. 어쨌든 그렇지 않습니다. 이는 pipe:[758683]
정보 제공일 뿐이며 사용할 수 없습니다 .열려 있는).
보다 일반적으로 lsof
가능한 경우:
lsof -ad0 -p "$$" -Fn 2> /dev/null | sed -n 'n;s/^n//p'
(단, $$
쉘을 실행하는 프로세스의 pid이므로 표준입력이 리다이렉트되는 서브쉘에서는 아무런 효과가 없다)
이제 읽기 위해 반드시 파일을 다시 열 수는 없으며, 그렇게 하더라도 파일을 읽어도 동일한 데이터가 다시 제공되지 않을 수 있습니다(예를 들어 파이프를 생각해 보세요).
$ seq 3 > a
$ { cat; cat /dev/stdin; } < a
1
2
3
1
2
3
$ cat a | { cat; cat /dev/stdin; }
1
2
3
Linux에서 /dev/stdin
stdin을 여는 것이 일반 파일인 경우 파일은 처음부터 다시 읽히는 반면, 다른 시스템에서는 /dev/stdin을 여는 것이 더 비슷합니다 dup(0)
. 즉, 파일을 처음부터 다시 되감지 않습니다. 위의 첫 번째 예에서는 1\n2\n3\n
두 번이 아닌 한 번 출력됩니다 .
답변2
어떻게든 파일 내용을 저장해야 합니다. 변수를 사용할 수 있습니다.
content=`cat`
x=`echo "$content" | grep -o '>' | wc -l`
y=`echo "$content" | grep -o '<' | wc -l`
if [ "$x" -ne "$y" ]; then
echo "Mismatch!"
fi
echo $x
echo $y
또는 임시 파일( example.html
널 바이트가 포함된 경우 필수).
tmp=`mktemp`
trap "rm $tmp" EXIT
x=`grep -o '>' "$tmp" | wc -l`
y=`grep -o '<' "$tmp" | wc -l`
if [ "$x" -ne "$y" ]; then
echo "Mismatch!"
fi
echo $x
echo $y
표준 입력에서 파일 내용을 읽을 필요가 없으면 파일 이름을 스크립트에 인수로 전달할 수 있습니다.
x=`grep -o '>' "$1" | wc -l`
y=`grep -o '<' "$1" | wc -l`
if [ "$x" -ne "$y" ]; then
echo "Mismatch!"
fi
echo $x
echo $y
다음과 같이 스크립트를 호출하십시오.
$ ./myscript.sh example.html
답변3
작업에 대한 한 가지 가능성은 다음과 같습니다.
#!/bin/bash
if [[ -n $1 ]]; then
if [[ ! -f $1 ]] || [[ ! -r $1 ]]; then
echo >&2 "File \`$1' not found or not readable."
exit 1
fi
exec "$0" < "$1"
fi
declare -A hary
while read c; do
(( ++hary[$c] ))
done < <(grep -o '[<>]')
echo "> ${hary[>]}"
echo "< ${hary[<]}"
이 스크립트를 호출하면개수 불일치(더 짧은 이름을 선택할 수 있습니다.) 파일 이름을 사용하거나 사용하지 않고 사용할 수 있습니다. 여러 가지 가능성:
$ countmismatched example.html
$ countmismatched < example.html
$ cat example.html | countmismatched
출력은 다음과 유사합니다.
> 41
< 42
불일치를 감지해야 하는 경우 스크립트 끝에 다음을 추가하세요.
if (( hary[<]} != hary[>] )); then
echo "Mismatched brackets"
else
echo "It's all good"
fi
아니면 좀 더 명시적인 것:
((difference=hary[<]-hary[>]))
if (( difference>0 )); then
echo "Mismatched brackets: you have $difference more <'s than >'s"
elif (( difference<0 )); then
echo "Mismatched brackets: you have $((-difference)) more >'s than <'s"
else
echo "It's all good"
fi