Script Bash para exibir listagem de diretórios dá erro

3

Eu escrevi um script bash simples (eu sou muito novo para ele, você sabe!) para aceitar um diretório como argumento e imprimir sua listagem, testando arquivos e diretórios. Veja como eu me aproximei:

#!/bin/bash
# Lists all files and directories (non-recursively) in a specified directory

if [ $# -gt 1 ]; then
    echo "Error. Please specify only one directory. ($#)"
    exit
fi

if [ -z $1 ]; then
    echo "No directory specified. Exiting."
    exit
fi

echo "Listing for $1:"

$dirs='ls $1'
echo "Dirs: $dirs" # Just to confirm if all is well

# Loop through and print
for i in $dirs;
do
    if [ -f $i ]; then
        echo "File: $i"
    elif [ -d $i ]; then
        echo "Directory: $i"
    fi
done

O problema está no meu loop. Quando executo esse script e o alimento do meu diretório pessoal, recebo este erro:

./list_files_and_dirs.sh: line 16: =Calibre: command not found

Eu sei que estou cometendo um erro na substituição de comando envolvendo variáveis, mas eu não sei o quê. Alguém por favor me ajude!

================= Atualização =================

Aqui está o novo código (seção final) conforme as entradas das respostas:

dirs='ls "$1"'
#echo "Dirs: $dirs" # Just to confirm if all is well

IFS=$'\n'

# Loop through and print
for i in $dirs;
do
    if [ -f "$i" ]; then
        echo "File: $i"
    elif [ -d "$i" ]; then
        echo "Directory: $i"
    fi
done
    
por dotslash 13.09.2015 / 18:16

2 respostas

9

Nota: Eu presumi que você está ensinando a si mesmo Bash. Não use este código em produção. find "$directory" -maxdepth 1 -type d irá te dar os diretórios, -type f irá te dar os arquivos.

Como está reclamando da linha 16, vamos dar uma olhada:

$dirs='ls $1'

Se você deseja atribuir a uma variável, não inclua o $ . Eu estou supondo que você quis dizer:

dirs='ls $1'

O que está acontecendo agora é:

  • $dirs provavelmente está vazio, então é substituído por nada.
  • O comando ls é executado e sua saída é substituída no 'comando'.
  • O primeiro arquivo no seu diretório é chamado Calibre , deixando você com o comando: =Calibre x y z ...
  • =Calibre não é um comando válido, portanto, o erro.

No entanto, ainda não chegamos lá: isso vai dar errado se houver espaços em qualquer um dos nomes de arquivos. Para corrigir isso, você precisa fazer mais:

  • Você precisa incluir IFS=$'\n' em algum lugar antes do loop for . Isso define o separador de campos para o caractere de alimentação de linha, que impede o loop for de dividir os arquivos nos espaços ou guias (é tecnicamente possível que um arquivo tenha um avanço de linha em seu nome de arquivo também: é improvável que você já encontrar tal arquivo e ele não causará problemas sérios neste caso se você se deparar com tal arquivo, mas vale a pena estar ciente da possibilidade caso isso realmente importe).
  • Para que um nome de arquivo com espaços não se transforme em vários argumentos diferentes para -f e -d , é necessário colocar aspas $i . (Então: [ -f "$i" ] e [ -d "$i" ] . Para suportar diretórios com espaços neles, você deve fazer o mesmo para $1 onde é usado.
por 13.09.2015 / 18:32
5

Marinus já explicou por que você estava recebendo esse erro. Gostaria de salientar que não há necessidade de ls aqui. Dessa forma, você evita todos os problemas que surgem com análise de sua saída . Você poderia apenas fazer:

#!/bin/bash
# Lists all files and directories (non-recursively) in a specified directory

if [ "$#" -gt 1 ]; then
    echo "Error. Please specify only one directory. ($#)"
    exit
fi

if [ -z "$1" ]; then
    echo "No directory specified. Exiting."
    exit
fi

echo "Listing for $1:"

# Loop through and print
for i in "$1"/*;
do
    if [ -f "$i" ]; then
        echo "File: $i"
    elif [ -d "$i" ]; then
        echo "Directory: $i"
    fi
done
    
por 13.09.2015 / 19:05