Em um Mac, como posso listar o conteúdo de um diretório não atual sem mostrar os arquivos de backup (terminando com ~), de preferência com o comando BSD ls?

Em um Mac, como posso listar o conteúdo de um diretório não atual sem mostrar os arquivos de backup (terminando com ~), de preferência com o comando BSD ls?

Meu sistema:

  • SO: MacOS/Mac OS X (Mojave 10.14.5)
  • Núcleo do sistema operacional: Darwin (18.6.0)
  • Kernel: Kernel Darwin/XNU (18.6.0/xnu-4903.261.4~2/RELEASE_X86_64)
  • ls: versão desconhecida, mas man lsfornece uma página do Manual de Comandos Gerais do BSD
  • Cartuchos:
    • Bash: GNU bash, versão 5.0.7(1)-release (x86_64-apple-darwin18.5.0)
    • Zsh: zsh 5.7.1 (x86_64-apple-darwin18.2.0)

No MacOS, em um terminal CLI usando um shell como bash ou zsh, gostaria de usar o comando (BSD) ls(ou talvez uma ferramenta igualmente comum e útil) para listar o conteúdo de um diretório diferente do diretório de trabalho atual , onde todos os arquivos, exceto aqueles que terminam com um til ( ~), são mostrados.

Excluindo a última estipulação, lsnaturalmente realiza esta tarefa quando o diretório não atual é usado como argumento para ls: ls argonde argé um caminho absoluto ou relativo para o diretório não atual (como /absolute/path/to/directory,, ~/path/from/home/to/directoryou path/from/current/dir/to/directory).

Eu sei como listar conteúdos que não são de backup no diretório atual, usando a expansão de nome de arquivo (também conhecida como "globbing") e a -dopção (para listar diretórios e não seu conteúdo), assim: ls -d *[^~](ou ls -d *[!~]). Quero o mesmo tipo de resultados, mas para um diretório não atual.

Quase posso conseguir o que desejo usando ls -d arg/*[^~], onde argé o mesmo descrito acima, mas os resultados mostram o caminho para cada elemento de conteúdo (ou seja, cada arquivo e diretório no diretório de interesse). Quero lsexibir cada elemento sem o caminho para ele, como é feito com ls arg.

No Linux, usando o comando GNU ls, posso conseguir exatamente o que desejo usando a -Bopção de não listar arquivos de backup ls -B arg:. Embora seja isso que eu queira, gostaria de conseguir isso usando ferramentas nativas do MacOS, de preferência o BSD ls.

Nota: não quero usar grep(por exemplo, ls arg | grep '.*[^~]$'), pois grepaltera a formatação e a coloração da saída.

Recapitulação da pergunta: em um Mac, como posso listar o conteúdo de um diretório não atual, mas não os arquivos de backup, de preferência usando ls?

Responder1

Você poderia executar lsem um subshell:

(cd arg; ls -d *[^~])

Responder2

Usando bashe sua GLOBIGNOREvariável shell, junto com o macOS basename:

$ mkdir dir
$ touch dir/file{1,2}{,~}
$ ls -R
dir

./dir:
file1   file1~  file2   file2~
$ GLOBIGNORE=*~
$ ls -d dir/*
dir/file1       dir/file2
$ basename -a dir/*
file1
file2

Definir GLOBIGNOREuma lista de :padrões delimitados fará com que a conclusão do nome do arquivo ignore esses padrões.

O basenameutilitário no macOS aceita mais de um nome de caminho se você usar sua -aopção e retornará uma lista que consiste apenas nas partes do nome de arquivo desses nomes de caminho.

Em vez de usar GLOBIGNORE(que fornece uma maneira mais genérica de ignorar certas expansões de padrão de nome de arquivo), você poderia obviamente usar seu padrão *[!~](observe que !nega uma classe de caracteres no shell, enquanto ^nega uma classe de caracteres em expressões regulares):

unset GLOBIGNORE
basename -a dir/*[!~]

... ou você pode simplesmente instalar GNU coreutils do Homebrew e usar gls -Bcomo está acostumado em sistemas Linux.

Responder3

A resposta concisa é usar um subshell para executar o comando no diretório não atual:

(cd arg; ls -d *[^~])

Mas para criar uma função geral que funcione tanto para o diretório atual quanto para qualquer diretório não atual, podemos adicionar o seguinte a .bashrc(ou a bashrc_aliases_lsBSD, originado por .bashrc):

alias ls='/bin/ls'
alias   l=''
unalias l
function l () { ( if [[ -n "$@" ]]; then cd "$@"; fi ; /bin/ls -d *[^~] ) }

Se desafiarmos a preferência mencionada acima para usar o BSD, podemos usar o GNU lssem problemas instalando os utilitários principais do GNU (por exemplo, via brew install coreutils) e criando os aliases desejados (em vez de usar o código acima) em .bashrc(ou em bashrc_aliases_lsGNU, originado por .bashrc) :

alias ls='/usr/local/bin/gls'
alias l='/usr/local/bin/gls -B'

Minha própria solução atual é usar essas duas construções e alternar entre elas quando desejado usando uma variável que eu chamo LS_TYPEe uma função que eu chamo ls-switch(definida em bashrc_aliases, originada por .bashrc), que origina um dos dois arquivos de configuração contendo essas duas construções:

function ls-switch () {
    if [[ $LS_TYPE = "GNU" ]] ; then
        LS_TYPE="BSD"
        source ~/.config/bash/bashrc_aliases_lsBSD
    elif [[ $LS_TYPE = "BSD" ]] ; then
        LS_TYPE="GNU"
        source ~/.config/bash/bashrc_aliases_lsGNU
    fi
}

Com esse arranjo, os comportamentos padrão de lse lsão definidos .bashrccom a primeira definição LS_TYPEe escolha de qual arquivo de configuração será originado, por exemplo:

LS_TYPE="BSD"
source ~/.config/bash/bashrc_aliases_lsBSD

informação relacionada