Inverte as linhas correspondentes, separadas por NUL

4

Estou escrevendo algo que lida com correspondências de arquivos e preciso de uma operação de inversão. Eu tenho uma lista de arquivos (por exemplo, find . -type f -print0 | sort -z >lst ) e uma lista de correspondências (por exemplo, grep -z foo lst >matches - note que este é apenas um exemplo; matches pode ser qualquer subconjunto arbitrário (incluindo vazio ou completo) ou lst ), e agora quero inverter essa lista.

Antecedentes: estou meio que implementando algo como encontrar (1) exceto listas de arquivos (embora os arquivos existam em o sistema de arquivos no ponto de chamada, a lista pode ter sido pré-filtrada). Se a lista de arquivos não fosse tão grande, eu poderia usar find "${files[@]}" -maxdepth 0 -somecondition -print0 , mas mesmo o uso moderado do que estou escrevendo ultrapassaria o limite de tamanho do Linux ou do BSD argv .

Se as linhas não fossem separadas por NUL, eu poderia usar comm -23 lst matches >inverted . Se as correspondências não fossem separadas por NUL, eu poderia usar grep -Fvxzf matches lst . Mas, dos geradores que mencionei no primeiro parágrafo, ambos são.

Suponha que as ferramentas GNU estão instaladas, portanto, isso não precisa ser portável além de, por exemplo, Debian, como eu estou usando find -print0 , sort -z e amigos já (embora alguns BSDs tenham, então se isso pode ser feito em "mais portável", eu não vou reclamar).

Estou tentando fazer a reutilização de código aqui; Além disso, comm -23 é basicamente a ferramenta perfeita para isso, exceto que ele não suporta a alteração do separador de linha de entrada (ainda), e comm é uma ferramenta subestimada e pouco conhecida. Se a caixa de ferramentas Unix / Linux não oferecer nada sensato, provavelmente reimplementarei uma forma de comm -23 (reduzida a apenas este caso de uso) no shell, já que o script (por outros motivos) requer um shell que Acontece para suportar read -d '' para entrada delimitada por NUL, mas isso vai ser lento (e esforço ... eu postei isso no final do dia de trabalho na esperança de que alguém tenha uma idéia para quando eu pegar isso amanhã ou no dia 28 ).

    
por mirabilos 23.12.2015 / 15:21

2 respostas

6

Se o seu comm suporta entrada sem texto (como as ferramentas GNU geralmente fazem), você sempre pode trocar NUL e nl (aqui com uma substituição de processo de suporte ao shell (você tem algum plano para isso em mksh btw?)) :

comm -23 <(tr '
comm -23 <(tr '%pre%\n' '\n%pre%' < file1) <(tr '%pre%\n' '\n%pre%' < file2) |
  tr '%pre%\n' '\n%pre%'
\n' '\n%pre%' < file1) <(tr '%pre%\n' '\n%pre%' < file2) | tr '%pre%\n' '\n%pre%'

Essa é uma técnica comum .

    
por 23.12.2015 / 22:37
-2

Se você estiver usando o grep para correspondência de pesquisa, poderá usar a opção -v do grep para ter uma linha que não corresponda.

    
por 23.12.2015 / 15:25