Eu tenho que escrever um script bash que contará símbolos como "<" e ">" do stdin.
Por exemplo:
$ ./myscript.sh <example.html
> - 20
< - 21
Found mismatching brackets!
Eu fiz isso:
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
Este é um bom caminho? Não sei como obter o nome do arquivo “example.html” do stdin.
Responder1
O ponto principal stdin
é que pode ser qualquer coisa, pode ser, por exemplo, um cano, um soquete de rede, um arquivo normal, um dispositivo, pode estar no meio de um arquivo normal quando seu script é iniciado ... Se você puder ' Se você não processar os dados de uma só vez, então você se limita apesquisávelarquivos, ou seja, arquivos normais e alguns arquivos de dispositivo, ou terão que armazenar as informações de alguma forma (em um arquivo temporário ou memória...). É possível aqui obter todas as informações de uma vez.
Por exemplo, você poderia fazer:
$ grep -o '[<>]' < a.html | sort | uniq -c
82 <
82 >
POSIXamente:
fold -w 1 a.html | grep '[<>]' | sort | uniq -c
Para detectar incompatibilidade:
if fold -w 1 a.html | awk '{n[$0]++}
END{exit(n["<"]!=n[">"])}'
then
echo match
else
echo mismatch
fi
Agora, para responder a pergunta do assunto, no Linux, você pode encontrar um “nome” para stdin com:
readlink -f /dev/stdin
Exemplo:
$ readlink -f /dev/stdin < a
/home/chazelas/a
$ : | readlink -f /dev/stdin
/proc/20238/fd/pipe:[758683]
(20238 acima é o pid de readlink
, então esse caminho não será de muita utilidade após readlink
a saída, e não seria de qualquer maneira, isso pipe:[758683]
é apenas informativo, não pode seraberto).
E de forma mais geral, se lsof
estiver disponível:
lsof -ad0 -p "$$" -Fn 2> /dev/null | sed -n 'n;s/^n//p'
(Porém, $$
sendo o pid do processo que executou o shell, ele não funcionaria em subshells que tiveram seu stdin redirecionado)
Agora, você não será necessariamente capaz de reabrir esse arquivo para leitura e, mesmo quando o fizer, a leitura desse arquivo poderá não fornecer os mesmos dados novamente (pense em pipes, por exemplo).
$ seq 3 > a
$ { cat; cat /dev/stdin; } < a
1
2
3
1
2
3
$ cat a | { cat; cat /dev/stdin; }
1
2
3
No Linux, abrir /dev/stdin
se stdin for um arquivo normal, irá ler o arquivo desde o início novamente, enquanto em outros sistemas, abrir /dev/stdin é mais parecido com um dup(0)
, ou seja, não retrocede o arquivo para o início (no primeiro exemplo acima , a saída seria 1\n2\n3\n
uma vez em vez de duas).
Responder2
Você terá que armazenar o conteúdo do arquivo de alguma forma. Você pode usar uma variável.
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
Ou um arquivo temporário (necessário se example.html
contiver bytes nulos).
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
Se a leitura do conteúdo do arquivo stdin não for um requisito, você poderá passar o nome do arquivo como argumento para o script.
x=`grep -o '>' "$1" | wc -l`
y=`grep -o '<' "$1" | wc -l`
if [ "$x" -ne "$y" ]; then
echo "Mismatch!"
fi
echo $x
echo $y
Chame o script assim:
$ ./myscript.sh example.html
Responder3
Uma possibilidade para sua tarefa é:
#!/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[<]}"
Se você chamar esse scriptcontagem incompatível(você pode escolher um nome mais curto), você poderá usá-lo com ou sem nome de arquivo. Algumas possibilidades:
$ countmismatched example.html
$ countmismatched < example.html
$ cat example.html | countmismatched
A saída será algo como:
> 41
< 42
Se você precisar detectar incompatibilidades, adicione no final do script:
if (( hary[<]} != hary[>] )); then
echo "Mismatched brackets"
else
echo "It's all good"
fi
ou algo mais explícito:
((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