Encontre o máximo dos comprimentos de todos os nomes de arquivos em um diretório

1

Eu tenho que escrever um script que leva um nome de diretório como um argumento e grava na saída padrão o máximo dos comprimentos de todos os nomes de arquivos nesse diretório. Se o argumento da função não for um nome de diretório, escreva uma mensagem de erro.

Como posso fazer isso

    
por MA VI 03.02.2018 / 21:12

1 resposta

2

Um script em vez de uma função. Isso imprime o número de caracteres no nome de arquivo mais longo, que é o que eu entendi que você queria:

#!/bin/bash

# include hidden files
shopt -s dotglob
# if the first argument is a directory
if [ -d "" ]; then
    # move to that directory
    cd ""
    # set a variable to 0
    long=0
    # loop over all the files
    for i in *; do
        # print the filename - remove this line after testing
        echo "$i"   
            # if the length of the current filename is longer 
            # than the value of the variable long, assign the
            # length of the current filename to long 
            (( (${#i} > $long) )) && long=${#i}
    done
        # print the value of long
        echo $long
    # if the first argument wasn't a directory, print an error
    else
        printf "%s\n" "Not a directory"
fi

Isso faz uso da configuração dotglob , o que faz com que globbing com * inclua arquivos ocultos. Para ver o efeito disso, execute esses comandos em seu diretório inicial:

ls -d *
shopt -s dotglob
ls -d *

Para desativar as configurações de shopt , use -u , por exemplo, shopt -u dotglob .

Precisamos verificar se o argumento é um diretório, então usamos if e o comando test (em seu [ form) que tem um teste para diretórios, -d :

if [ -d "" ]; then

isso significa que, se o primeiro argumento passado ao script for o nome de um diretório existente, faça o seguinte. é o primeiro argumento, e o colocamos entre aspas duplas para impedir que o shell execute outras expansões no valor da variável.

Precisamos entrar no diretório, porque precisamos obter o comprimento do nome do arquivo, não o caminho inteiro (absoluto ou relativo). Nós não queremos isso:

$ for i in ~/*; do [ -d "$i" ] && echo "$i"; done
/home/zanna/custom
/home/zanna/Desktop
/home/zanna/Documents
/home/zanna/Downloads
...

porque se contarmos o comprimento de $i , obteremos o comprimento do caminho completo. Poderíamos fazer algumas artimanhas de processamento de texto (e talvez alguns truques mais inteligentes que eu não conheço) para me livrar do caminho, mas analisar nomes de arquivos geralmente não é confiável e se mudarmos de diretório podemos facilmente obter o shell para contar caracteres usando ${#var} para dar o comprimento de var (acredito que isso contenha caracteres e não bytes). Observe que os scripts são executados em um shell filho, não no shell atual, portanto, se um script mudar de diretório, o diretório de trabalho do shell que chama o script não é afetado.

Meu script usa for para percorrer os arquivos no diretório. A linha que faz o trabalho é

(( (${#i} > $long) )) && long=${#i}

Isso significa que, se o comprimento do valor atual de i for maior que o valor atual de long , atribua o comprimento de i a long . Como primeiro definimos long para 0, o primeiro nome de arquivo sempre será maior que long (porque é o mais curto possível). Posteriormente, somente o tamanho dos nomes de arquivos mais longos poderá substituir o valor de long . Como sabemos que ${#i} e long contêm apenas números inteiros, não precisamos protegê-los com aspas duplas. (( cria um contexto aritmético no Bash para que possamos usar > com seu significado matemático (graças ao muru para apontar isso para mim em outro lugar).

    
por Zanna 05.02.2018 / 23:28