Eu estou procurando por uma linha única elegante (por exemplo, awk
) que encurte uma string de um caminho Unix usando o primeiro caractere de cada nível pai / intermediário, mas o nome completo da base. Mais fácil de mostrar por exemplos:
/path/to/file
→/p/t/file
/tmp
→/tmp
/foo/bar/.config/wizard_magic
→/f/b/./wizard_magic
/foo/bar/.config/wizard_magic
→/f/b/.c/wizard_magic
À luz dos pontos positivos de @ MichaelKjörling e @ChrisH abaixo, este exemplo mostra como podemos mostrar os dois primeiros caracteres quando o primeiro caractere é um ponto.
/f/b/.c/wizard_magic
. O ponto geralmente é tão comum em um diretório específico que é uma pista muito pequena de onde você deve procurar..
normalmente significa apenas "diretório atual". O/f/b/./wizard_magic
mesmo acontece com o/f/b/wizard_magic
fato de o elemento path ser./
compactado em um elemento path vazio.Respostas:
Para este arquivo de teste:
As abreviações podem ser geradas com este código awk:
Edit1: Usando dois caracteres para nomes de pontos
Esta versão abrevia nomes de diretório para um caractere, exceto para nomes que começam com os
.
quais são abreviados para dois caracteres:Como funciona
-F/
Isso diz ao awk para usar uma barra como o separador de campos na entrada.
for (i=1;i<NF;i++) $i=substr($i,1,1)
Isso faz um loop em cada campo, exceto o último, e o substitui apenas pelo seu primeiro caractere.
EDIT1: Na versão revisada, aumentamos o comprimento da substring 2 quando o campo começa com
.
.1
Isso informa ao awk para imprimir a linha revisada.
OFS=/
Isso informa ao awk para usar uma barra como o separador de campos na saída.
fonte
‥
separador:awk -F/ '{for (i=1;i<NF;i++) $i=substr($i,1,1+($i~/^[.]/))(i==1||length($i)<2?"":"‥")} 1' OFS=/ <<<$PWD
dá:/foo/bar/.config/wizard_magic
→/f‥/b‥/.c‥/wizard_magic
Muito fácil no sed (supondo que não haja novas linhas nos nomes dos arquivos):
Menos fácil no awk porque não possui referências anteriores (exceto no Gawk, mas com uma sintaxe desajeitada):
No zsh (com o caminho
$full_path
):fonte
\1
no texto de substituição não significa uma referência a um grupo de captura no padrão. Uma referência anterior é uma referência anterior, não importa onde você a utilize.você pode fazer isso como:
e aqui está um
sed
:que chega bem perto de fazer as mesmas coisas que a função faz abaixo. ele não abrevia com tildes ou insere a
$PWD
cabeça de uma não barra invertida como a função (e de fato, nunca imprime a barra invertida), mas isso pode ser tratado posteriormente. ele processa componentes de caminho nulo, pontos únicos e elimina..
casos.dado o mesmo
man
caminhocd
acima, ele imprime:também imprimirá um ou dois pontos iniciais extras para cada componente do caminho que começa com esse e não é apenas um ou dois pontos.
você perguntou sobre fazer mais do que o caractere para um componente de caminho que começa com a
.
. para fazer isso, imaginei que cada componente precisaria de atenção individual de qualquer maneira e, como estava curioso, tentei trabalhar um caminho canônico sem o diretório de alterações. depois de alguma tentativa e erro, decidi que a única maneira de fazer isso direito era fazê-lo duas vezes - para trás e para frente:para que nunca mude o diretório ou tente confirmar a existência de qualquer componente do caminho, mas aperta
/
delimitadores repetidos e elimina/./
completamente os componentes de ponto único e processa/../
os componentes de ponto duplo adequadamente.Quando
$IFS
é definido como um caractere que não é um espaço em branco , uma sequência de dois ou mais$IFS
caracteres resultará em um ou mais campos nulos. para que várias barras consecutivas funcionem com argumentos de valor nulo. o mesmo vale para um$IFS
personagem principal . e assim, quando seset -- $1
divide, se o resultado$1
for nulo, ele começará com uma barra, caso contrário,${1:+$PWD}
se não for nulo, insiro$PWD
. em outras palavras, se o primeiro argumento não começar com uma barra, ele será$PWD
anexado. é o mais próximo possível da validação de caminho .caso contrário, o primeiro
for
loop inverte recursivamente a ordem dos componentes do caminho, como:... ao fazer isso, ignora qualquer componente de ponto único ou nulo, e por
..
isso ...... a segunda passagem inverte esse efeito e, ao fazê-lo, comprime cada componente em 2 pontos + caractere ou 1 ponto + caractere ou caractere .
portanto, deve seguir um caminho canônico, independentemente da existência.
eu adicionei / subtraí um pouco ao segundo loop. agora
set
é menos frequente (apenas uma vez para cada[!./]*
componente) ecase
avaliações de padrão de curto-circuito na maioria das vezes (graças ao padrão mencionado acima) e inclui uma avaliação de correspondência de chamada de cauda contra~
. se todo ou uma parte inicial (dividida em componentes inteiros) do caminho finalmente canônico puder corresponder~
, o bit correspondente será retirado e um literal~
será substituído. para fazer isso, eu tive que manter uma cópia completa do caminho ao lado do abreviado também (porque combinar o caminho abreviado~
provavelmente não seria muito útil) , e isso é mantido$3
. o últimowhile
A ramificação de loop é executada apenas se~
corresponder a um subconjunto de$3
.se você executá-lo com o
set -x
rastreamento ativado, poderá vê-lo funcionar.fonte
O tema Zsh "suspeito" do Oh My Zsh contém um trecho de Perl para fazer exatamente isso que tem suporte a Unicode:
fonte
Deseja ter o nome abreviado de s ou usá-lo para sua linha de comando?
Para a linha de comando, tenho as seguintes sugestões:
A conclusão do arquivo no seu shell não ajuda?
Às vezes, você tem sorte e não precisa fazer algo especial:
Quando você tem apenas alguns diretórios nos quais está interessado, pode usar aliases:
Ou você pode configurar variáveis para seus dirs favoritos
Eu acho que essas opções fazem mais sentido do que tentar resolver isso com uma função definida em .bashrc (ou .profile) como
e chamando essa função x com espaços entre suas letras:
fonte