Shell script e cacls

O problema: um colega de trabalho queria checar as permissões de acesso de uma grande árvore de pastas em um servidor Windows. Muitos níveis de subpastas e permissões diferentes em cada uma. Por grande árvore de pastas, entenda por volta de umas 43000 pastas.

Eu não sei dizer se tem ferramenta mais fácil pra fazer o que ele queria, ou se um script VBS poderia resolver; eu até sugeri VBS, mas nenhum de nós dois conhecíamos o suficiente e aprender para resolver o problema iria tomar algum tempo. Então, ele e eu tomamos rotas usando ferramentas já conhecidas. Ele queria gerar uma saída de texto de cada pasta, usando o comando cacls do Windows, que permite listar e alterar as permissões via linha de comando. A saída desse comando é similar a isto:

Os nomes foram trocados para preservar os personagens.

Os nomes foram trocados para preservar os personagens.

Ou seja: o nome completo da pasta em questão, seguido das permissões. Havendo mais de uma permissão, elas aparecerão nas linhas seguintes, identadas com espaços para ficarem na mesma coluna que a primeira permissão listada (cuja coluna dependerá do tamanho do nome da pasta/arquivo listado).

Meu colega me perguntou se tinha alguma forma de rodar estas saídas em um script de forma a acrescentar o nome de pasta a cada uma das permissões subsequentes, de forma a facilitar a verificação; por exemplo, a listagem acima ficaria assim (usando : para separar nomes de pasta, de usuário/grupos e permissões):

\\stgreceita1\rfoc$\compartilhamentos\OC\DIESP\DIJUT\18 Controle de PL:BUILTIN\Administradores:(OI)(CI)F
\\stgreceita1\rfoc$\compartilhamentos\OC\DIESP\DIJUT\18 Controle de PL:RFOC\Domain Admins:(OI)(CI)R
\\stgreceita1\rfoc$\compartilhamentos\OC\DIESP\DIJUT\18 Controle de PL:RFOC\LS_COMP_DIESP_R:(OI)(CI)R
\\stgreceita1\rfoc$\compartilhamentos\OC\DIESP\DIJUT\18 Controle de PL:AUTORIDADE NT\SYSTEM:(OI)(CI)F

Solução: tentei fazer de cara com o sed, tentando descobrir uma forma de pegar tudo o que aparecia na linha antes do último espaço e repetir nas demais linhas, substituindo os espaços da linha; mas acabei ficando com este two-liner que deu conta do recado:

caminho=$(cat arq.txt | awk '(NR==1) { printf $1; for(i=2; i<nf ; i++) { printf " "; printf $i } }' | tr '\\' '/')
cat arq.txt | sed 's/acesso especial/acesso_especial/' | awk "{ print \"$caminho\:\"\$NF }" | tr '/' '\\' >> saida.txt

Sendo arq.txt o arquivo que contém a saída do cacls para uma pasta, e saida.txt o arquivo de saída. Depois bastou criar um loop para executar esses dois comandos para cada arquivo de entrada e pronto.

O primeiro comando pega o caminho da pasta, lendo apenas a primeira linha do arquivo e capturando tudo até o último espaço; depois esse caminho é acrescentado pelo segundo comando no começo de cada linha, retirando os espaços de identação. O sed da segunda linha está lá apenas para tratar o caso do texto “acesso especial”, que contém um espaço e atrapalhava o funcionamento do awk seguinte.

Como disse, pode ser que uma linguagem de script já própria do Windows como VBS ou Powershell resolvesse o problema de forma mais simples, mas como meu colega queria uma solução rápida resolvemos desta forma. Conhecer um pouco de shell e ter um cygwin instalado na máquina Windows ajudou bastante 😉

Anúncios

Extraindo o último elemento de uma linha com o awk

awk, o mastigador de linhas de texto

awk, o mastigador de linhas de texto

Hoje surgiu a necessidade de manipular, via script (shell), um arquivo texto e pegar o último elemento de uma linha, que é um código. Como a linha de exemplo abaixo:

DISSE0074I Operation successfully submitted. Distribution ID is 1234567890.123456.

No caso eu preciso pegar o código numérico no fim da linha. Geralmente eu usaria apenas o comando cut, como: cut -d’ ‘ -f8, mas e se a mensagem variar de tamanho (quantidade de palavras)? Como saber o índice do último elemento?

Entra em ação o awk. Usando awk ‘{print $8}’ dá pra imprimir o elemento número 8; e há a variável NF que informa a quantidade de campos. Então dá pra extrair o último campo assim:

cat arquivo.txt | awk ‘{print $NF}’

Perfeito para o que eu queria.

Bash Shell Shortcuts

All about Linux: Bash Shell Shortcuts

English version below.

Algumas combinações de teclas úteis para se usar a linha de comando no Linux.

Diga-se de passagem, muitas destas combinações de teclas são parecidas com as usadas no editor de textos Emacs. Por exemplo: para mover o cursor para o começo ou fim da linha usa-se ctrl+a e ctrl+e; para saltar de uma palavra para a outra, alt+b e alt+f; para capitalizar (mudar de minúscula para maiúscula), alt+c e assim por diante.

Mais algumas coisas interessantes sobre o shell: Simplify data extraction using Linux text utilities


Some useful key bindings to use while in Linux command line.

Just as a side comment, some of these bindings are similar to the ones used by the text editor Emacs. For example: to move the cursor to the start or the end of the line, use ctrl+a or ctrl+e; to jump from one word to another, alt+b and alt+f; to capitalize the current word/character use alt+c and so on.

Some more shell goodies: Simplify data extraction using Linux text utilities

Moving files under Unix

English version below.

Em um sistema Unix, para copiar muitos arquivos de um diretório para outro (por exemplo, copiar todos os arquivos de uma partição inteira), o comando cp pode não ser o mais indicado: ele pode ter alguns problemas tratando arquivos incomuns, como por exemplo pipes e dispositivos. Nestes casos, o comando tar pode ser mais indicado.

Por exemplo, para copiar todo o conteúdo do diretório /usr e subdiretórios para /mnt :
cd /usr
tar cfp - ./* |(cd /mnt; tar xvfp -)

O parâmetro p garante que as permissões de arquivo serão copiadas e restauradas. Usar – como nome do arquivo faz com que o tar leia/escreva na entrada/saída padrão ao invés de um arquivo normal. Por fim, chamar o segundo comando dentro de () faz com que este seja executado dentro de um ‘subshell’, recebendo em sua entrada padrão a saída do comando anterior, repassada via pipe.

Retirado do artigo Move an Entire File System on a Live Unix System – OSNews.com


In a Unix system, to copy a large amount of files from one directory to another (say, copying all files in a partition), the cp command may not be the best option: it may have some problems handling uncommon files, like pipes and devices. In this case, the tar command can be a better option.

For example, to copy all files from /usr and subdirectories to /mnt :
cd /usr
tar cfp - ./* |(cd /mnt; tar xvfp -)

The parameter p tells tar to preserve the file permissions. Using – as the file name makes tar to read from standard input or write to standard output, instead of a normal file. And since the second command is being called inside (), it is being runned in a \’subshell\’, receiving in its standard input the output from the previous command, sent to it via pipe.

Taken from the article Move an Entire File System on a Live Unix System – OSNews.com