Bash, 표준 입력 파일 이름?

Bash, 표준 입력 파일 이름?

표준 입력에서 나오는 "<" 및 ">"와 같은 기호를 계산하려면 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/stdinstdin을 여는 것이 일반 파일인 경우 파일은 처음부터 다시 읽히는 반면, 다른 시스템에서는 /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

관련 정보