stdin에서 "<" 및 ">"와 같은 기호를 계산하는 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
이 방법이 좋은가요? stdin에서 파일 이름 "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을 여는 것은 a와 유사합니다. 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
stdin에서 파일 내용을 읽는 것이 요구 사항이 아닌 경우 파일 이름을 스크립트에 인수로 전달할 수 있습니다.
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