Eu tenho arquivos em subdiretórios do diretório atual que podem ou não ter novas linhas no final; como posso encontrar arquivos que não possuem uma nova linha no final?
Eu tentei isso:
find . -name '*.styl' | while read file; do
awk 'END{print}' $file | grep -E '^$' > /dev/null || echo $file;
done
mas não funciona. awk 'END{print}' $file
imprime a linha antes de uma nova linha vazia, igual a tail -n 1 $file
.
awk 'END{print}' $file
: isso ignora totalmente o conteúdo do arquivo $ e, após terminar de analisar todos os arquivos contidos em "$ arquivo", ele adiciona uma nova linha. Como é a única coisa que o comando awk imprime, ele pode ser substituído por:printf '\n'
(sem nenhum mentino de $ file) e fazer a mesma coisa. Eu acho que não é isso que você estava com o objetivo de: (isto é imprimir a última linha do arquivo?)c
e o FreeBSD também, mas eu não percebi que ele está documentado como dependente da implementação: gnu.org/software/gawk/manual/… . Por isso não acontecer, mas nem sempre.Respostas:
Para esclarecer, o caractere LF (aka
\n
ou nova linha) é o delimitador de linhas , não é o separador de linhas. Uma linha não é finalizada, a menos que seja finalizada por um caractere de nova linha. Um arquivo que contém apenasa\nb
não é um arquivo de texto válido porque contém caracteres após a última linha. O mesmo para um arquivo que contém apenasa
. Um arquivo que contéma\n
contém uma linha não vazia.Portanto, um arquivo que termina com pelo menos uma linha vazia termina com dois caracteres de nova linha ou contém um único caractere de nova linha.
E se:
Saídas
\n
ou\n \n
, em seguida, o arquivo contém pelo menos uma linha vazia à direita. Se ele não produzir nada, então esse é um arquivo vazio, se gerar<anything-but-\0> \n
, então termina em uma linha não vazia. Além disso, não é um arquivo de texto.Agora, para usar isso para encontrar arquivos que terminam em uma linha vazia, OK é eficiente (especialmente para arquivos grandes), pois apenas lê os últimos dois bytes dos arquivos, mas primeiro a saída não é facilmente analisável programaticamente, especialmente considerando que é não é consistente de uma implementação
od
para a seguinte e precisamos executar umatail
e umaod
por arquivo.(para localizar arquivos que terminam em uma linha vazia) executaria o menor número possível de comandos, mas significaria ler o conteúdo completo de todos os arquivos.
Idealmente, você precisaria de um shell que possa ler o final de um arquivo sozinho.
Com
zsh
:fonte
are_textfiles () { nontext=0; rem="return 0 if all args are files with terminating newline, or n [=number of non-textfiles]" ; for f in "$@" ; do [ -f "$f" ] && { tail -c 1 "$f" | od -An -vtc | grep "\\n" ;} >/dev/null 2>&1 || ((nontext++)) ; done ; return $nontext ; }
. Use como:if ( are_textfiles this that otherthing ) ; then echo all are text files ; else echo "are_textfiles returned : $?" ; fi
Com
gnu sed
e um shell comozsh
(oubash
comshopt -s globstar
):isso verifica se a última linha de cada arquivo não está vazia; caso contrário, imprime o nome do arquivo.
Se desejar o contrário (imprima os nomes dos arquivos se a última linha estiver vazia), substitua-os
/./
por/^$/
fonte
-s
em ação antes. Obrigado GNU!Um arquivo de texto finalizado corretamente com uma última linha vazia termina em duas
\n
.Então, esperamos que isso
tail -c2
seja igual a$'\n\n'
.Infelizmente, as expansões de comando removem as novas linhas à direita. Vamos precisar de alguns ajustes.
Poderíamos até expandir um pouco para verificar quais arquivos não possuem uma nova linha à direita:
Observe que a nova linha pode ser alterada para algo como
$'\r\n
se necessário.Nesse caso, mude também
tail -c2
paratail -c4
.fonte
fonte
cat $file 2>&1 /dev/null
, ou se for somente Bashcat $file &> /dev/null
,.$file
todos os lugares ele é utilizado - e, por favor, use$(commands ...)
em vez de`backticks`
...