標準入力からの「<」や「>」などの記号を計算するには、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回ではなく1回出力されます。
答え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
NULLバイトが含まれている場合は必須)。
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
タスクの1つの可能性は次のとおりです。
#!/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