pax
pode ser realmente útil nesses casos. Na verdade, seria mais fácil se eu descobrisse um pax
que faz a opção -o listopt=...
especificada pelo POSIX mas, apesar do meu olhar, eu ainda tenho que encontrar um que faça. Eu uso o que o mirabilos mantém - o BSD pax
( mirabipax
?) - que é provavelmente o que a maioria dos outros faz até onde eu sei. De qualquer forma, você começa a regex nomes de arquivos - e listas de arquivos. Por exemplo:
(set -e; mkdir -p a/b c1/c2 d1/d2/d3
touch a/b/original-target a/b/new-target
cd c1/c2; ln -s ../../a/b/original-target
cd ../../d1/d2/d3; ln -s ../../../a/b/original-target)
Isso faz a sua árvore. Agora vou listar:
pax -ws'|\(\..*/original-target.*\)*.*||' ././ |
pax -cvs'|\(.*\)/original|/new|p' \
'././a/b/original-target' '*/original-target?*'
Que imprime ...
././d1/d2/d3/original-target >> ././d1/d2/d3/new-target
lrwxrwxrwx 1 mikeserv mikeserv 0 Dec 7 18:17 ././d1/d2/d3/new-target => ../../../a/b/new-target
././c1/c2/original-target >> ././c1/c2/new-target
lrwxrwxrwx 1 mikeserv mikeserv 0 Dec 7 18:14 ././c1/c2/new-target => ../../a/b/new-target
Ok, o primeiro pax
escreve um ustar
archive para stdout
. O -s
regex arg I entregue é mais frequentemente usado para alterar nomes de arquivos no fluxo - como eu faço aqui com o segundo pax
- mas com um truque ou dois ele também pode ser usado para filtrar arquivos adicionados ao arquivo em o primeiro lugar.
Você vê, qualquer nome de arquivo que termina vazio após a aplicação do -s
arg é especificado para ser removido do arquivo completamente. Então, eu uso um regex que corresponda a cada nome de arquivo, mas também remova todos os caracteres de cada um que não correspondam ao padrão salvo em
. Isso é necessário porque, embora seja possível selecionar facilmente arquivos dentro de um archive com base em um padrão, esse não é o caso quando -w
rite o archive - que depende de globs de shell e, portanto, não recorre.
Ainda assim, o regex como escrito ainda receberá /original-target
seguido por qualquer caractere e, do outro lado, um dos padrões que eu -c
omplement na minha seleção ao listar o arquivo é */original-target?*
- que será solte aí. Mesmo isso não é perfeito - quer dizer, talvez existam links que contenham esse padrão duas vezes, mas ... bem, é o que é - e é muito bom. Pode ser tratado com testes adicionais nas mesmas linhas. De qualquer forma, eu também -c
omplico uma correspondência para ././a/b/original-file
em si - e isso também é descartado da saída da lista.
No modo de lista - que é o que o pax
faz quando não -r
ead ou -w
rite - pax
lista com detalhes - no formato ls -l
- incluindo todos os soft vincular destinos como link => target
- mas somente depois de aplicar qualquer -s
args aplicável. Aqueles mesmos -s
args são impressos, independentemente do -v
quando o -s|...|...|p
o p
é aplicado no seguinte formato:
"%s>>%s\n", original pathname, new pathname
Por isso, obtemos as listagens separadas com o ././
que, de outra forma, não apareceria. Agora isso torna as coisas realmente fáceis, como espero que você concorde. Deixarei para o leitor decidir como se pode aplicar esse tipo de dados com ln
- deve ser bastante simples - mas você não deveria precisar fazer isso .
Na verdade, pax
é especificado para permitir que você altere o arquivo em r
ead ou w
rite time com opções cli para alterar itens como usuário, grupo, linkdata, nome do arquivo, origem do arquivo Estas são ferramentas de análise de arquivos incrivelmente poderosas - mas o mais perto que cheguei de pax
que as implementa é o GNU tar
e somente em parte. Eu não encontrei nenhum meio de afetar os tipos de arquivo de um cabeçalho - embora você deva ser capaz de fazer isso até certo ponto - com opções de cli, mesmo que não seja muito difícil fazer isso com um regex no próprio arquivo. Existe um campo de cabeçalho para estas coisas:
... 2 - Represents a symbolic link. The contents of the symbolic link shall be stored in the linkname field.
Outra coisa que realmente quero que um pax
faça é -o listopt=...
. Aqui está um trecho da seção de exemplos da especificação:
Using the option:
-o listopt="%M %(atime)T %(size)D %(name)s"
...overrides the default output description in Standard Output and instead writes:
-rw-rw--- Jan 12 15:53 2003 1492 /usr/foo/bar
Using the options:
-o listopt='%L\t%(size)D\n%.7' \
-o listopt='(name)s\n%(atime)T\n%T'
...overrides the default output description in Standard Output and instead writes:
/usr/foo/bar -> /tmp 1492
/usr/fo
Jan 12 15:53 1991
Jan 31 15:53 2003
Então, se você encontrar um pax
que faz isso ... bem, você sabe quem está procurando.