AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 717674
Accepted
HippoMan
HippoMan
Asked: 2022-09-18 16:42:28 +0800 CST2022-09-18 16:42:28 +0800 CST 2022-09-18 16:42:28 +0800 CST

Mesclando dois arquivos de texto não baseados em git com semântica semelhante à representação de conflitos de mesclagem do git

  • 772

Eu gostaria de mesclar dois gitarquivos de texto não baseados usando semântica semelhante a como gitdescreve "conflitos de mesclagem".

Por exemplo, suponha que eu tenha dois arquivos de texto com conteúdo semelhante, mas não idêntico, chamados file.1e file.2. Gostaria de realizar uma mesclagem desses dois arquivos em um terceiro arquivo, da seguinte forma:

hypothetical-merge-utility file.1 file.2 file.merged

Eu gostaria que produzisse file.merged, que listaria o conteúdo do arquivo e cada diff de uma maneira semelhante a esta:

common line 1 ...
common line 2 ...
common line 3 ...
<<<<<<< file.1
something unique from file.1
a second line of something unique from file.1
======= file.2
something unique from file.2
>>>>>>> end of diff
common line 4 ...
common line 5 ...
<<<<<<< file.1
something unique from file.1
======= file.2
something unique from file.2
a second line of something unique from file.2
>>>>>>> end of diff
common line 6 ...
common line 7 ...
... etc. ...

Em outras palavras, eu gostaria que cada diferença entre file.1e file.2se parecesse com a representação de um git"conflito de mesclagem".

Eu não me importo se delimitadores diferentes de <<<<<<<<, ========e >>>>>>>>são usados.

Eu sei que existem vários utilitários disponíveis para mesclar arquivos de texto no linux. No entanto, estou apenas procurando algo que apresente especificamente os dados mesclados de uma maneira semelhante à maneira que gitdescreve "conflitos de mesclagem".

Alguém conhece tal utilidade?

Agradeço antecipadamente.

ATUALIZAÇÃO : De acordo com a pergunta abaixo de Ed Morton, aqui está o conteúdo dos dois arquivos de teste ...

==== arquivo.1 ====

common line 1 ...
common line 2 ...
common line 3 ...
something unique from file.1
a second line of something unique from file.1
common line 4 ...
common line 5 ...
something unique from file.1
common line 6 ...
common line 7 ...

==== arquivo.2 ====

common line 1 ...
common line 2 ...
common line 3 ...
something unique from file.2
common line 4 ...
common line 5 ...
something unique from file.2
a second line of something unique from file.2
common line 6 ...
common line 7 ...
text-processing diff
  • 3 3 respostas
  • 48 Views

3 respostas

  • Voted
  1. HippoMan
    2022-09-18T17:08:17+08:002022-09-18T17:08:17+08:00

    NOTA : Embora eu considere isso uma "resposta" um tanto razoável, agora cheguei a outra "resposta" que acho melhor. Então, por favor, veja minha outra "Resposta", abaixo.

    Versão original desta "Resposta" ...

    Oh! Postei muito cedo aqui. Eu não estava ciente da -Dopção de linha de comando para diff, e agora percebo que posso fazer isso ...

    diff -D file.1 file.2 >file.merged
    

    Ele irá produzir o seguinte dentro de file.merged...

    common line 1 ...
    common line 2 ...
    common line 3 ...
    #ifdef file.1
    something unique from file.1
    a second line of something unique from file.1
    #else /* file.1 */
    something unique from file.2
    #endif /* file.1 */
    common line 4 ...
    common line 5 ...
    #ifdef file.1
    something unique from file.1
    #else /* file.1 */
    something unique from file.2
    a second line of something unique from file.2
    #endif /* file.1 */
    common line 6 ...
    common line 7 ...
    ... etc. ...
    

    Posso lidar com as linhas #ifdef, #else, e #endifda mesma forma que posso lidar com gitas linhas <<<<<<<<, ========, e >>>>>>>>.

    ATUALIZAÇÃO : ... e acabei de encontrar isso: https://stackoverflow.com/questions/16902001/manually-merge-two-files-using-diff

    Ele mostra como também posso fazer algo semelhante com o formato diff unificado. Dê diffuma -Uopção com um argumento enorme que seja maior que o número máximo de linhas em file.1e file.2. Por exemplo ...

    diff -U 99999999 file.1 file.2 | tail -n +4 >file.merged
    

    Em seguida, ele produzirá isso:

     common line 1 ...
     common line 2 ...
     common line 3 ...
    +something unique from file.2
    -something unique from file.1
    -a second line of something unique from file.1
     common line 4 ...
     common line 5 ...
    +something unique from file.2
    +a second line of something unique from file.2
    -something unique from file.1
     common line 6 ...
     common line 7 ...
     ... etc. ...
    

    As +linhas representam os dados exclusivos em file.2e as -linhas representam os dados exclusivos em file.1.

    E eu posso lidar com essas +e -linhas.

    • 2
  2. Ed Morton
    2022-09-19T09:01:22+08:002022-09-19T09:01:22+08:00

    Parece que você realmente não se importa com o formato de saída e, em vez disso, só quer saber como identificar quais linhas são de cada arquivo ou são comuns. Dá isso, que tal:

    $ diff --old-line-format=$'-%l\n' --new-line-format=$'+%l\n' --unchanged-line-format=$'=%l\n' file.1 file.2
    =common line 1 ...
    =common line 2 ...
    =common line 3 ...
    -something unique from file.1
    -a second line of something unique from file.1
    +something unique from file.2
    =common line 4 ...
    =common line 5 ...
    -something unique from file.1
    +something unique from file.2
    +a second line of something unique from file.2
    =common line 6 ...
    =common line 7 ...
    

    Desconfie de qualquer solução em que você tenha que testar o conteúdo das linhas para um indicador da fonte para essa linha (por exemplo, se você estiver procurando <<<<<<< file.1dizer o que é exclusivo file1- e se filecontiver uma linha que seja exatamente essa string? ) em vez de um indicador que está sempre e apenas presente em uma posição única em cada linha, pois o teste de qualquer string falhará se essa string puder estar em sua entrada. Com o acima, o primeiro caractere é sempre um indicador de onde a linha veio, portanto, não pode entrar em conflito com o possível conteúdo do arquivo. Se você REALMENTE quisesse obter exatamente o formato de saída de conflitos de mesclagem do git (o que eu não recomendo), você sempre poderia canalizar o acima para um script awk simples para imprimir<<< fileou o que você quiser quando o primeiro caractere da linha for alterado e, em seguida, remova esse caractere.

    • 0
  3. Best Answer
    HippoMan
    2022-09-19T12:31:39+08:002022-09-19T12:31:39+08:00

    Devido às limitações das soluções que postei originalmente na minha primeira "Resposta" aqui que envolve diff -D ...e diff -U ..., decidi escrever uma solução em python, usando o difflibmódulo do python.

    Eu o escrevi para produzir uma saída que parece relativamente semelhante à saída "conflito de mesclagem" do git. Ele utiliza delimitadores contendo as strings <<<<<<<<, ========, e >>>>>>>>, e como sabemos, isso pode levar a ambiguidades se o texto original contiver strings como esta. No entanto, esse mesmo problema com ambiguidades pode existir na saída de "conflito de mesclagem" de git, mas como estou confortável gite disposto a aceitá-lo lá, também estou confortável com essas ambiguidades em minha própria solução.

    A saída não é exatamente a mesma da gitsaída "conflito de mesclagem", mas é semelhante o suficiente para satisfazer meus desejos.

    Primeiro, aqui está o programa python (limpei o código python original que postei aqui e esta é a versão limpa). Eu chamo esse programa filemerge...

    #!/usr/bin/python3
    
    ### Take the diff's between two files and output
    ### the common and different lines in a manner
    ### which is very similar to the way that `git`
    ### depicts merge conflicts.
    
    import sys
    sys.dont_write_bytecode = True
    
    import os
    
    from difflib import unified_diff
    
    prog       = None
    diff_start = '<<<<<<<<'
    diff_sep   = '========'
    diff_end   = '>>>>>>>>'
    
    def main():
        if len(sys.argv) < 3:
            print(f'\nusage: {prog} file1 file2\n')
            return 1
    
        file1, file2 = sys.argv[1:3]
        data1        = None
        data2        = None
        missing      = []
    
        try:
            with open(file1, 'r') as f:
                data1 = f.readlines()
        except Exception:
            missing.append(file1)
    
        try:
            with open(file2, 'r') as f:
                data2 = f.readlines()
        except Exception:
            missing.append(file2)
            
        if missing:
            print(f'\nnot found: {", ".join(missing)}\n')
            return 1
    
        n1 = len(data1)
        n2 = len(data2)
        max_lines = (n1 + 1) if n1 > n2 else (n2 + 1)
        count = 0
        state = ''
        sep_printed = False
        next_file = ''
    
        for line in unified_diff(data1, data2, n=max_lines):
            count += 1
            if count < 4:
                continue
    
            # Every line which is returned by unified_diff()
            # is at least 2 characters long. Each of these
            # lines starts with either ' ', '+', or '-', and
            # each of these lines ends with a newline.
            line = line[:-1]
            ch0  = line[0]
    
            if ch0 == ' ':
                if state:
                    state = ''
                    if not sep_printed:
                        print(f'{diff_sep}{next_file}')
                    print(diff_end)
                sep_printed = False
                next_file = ''
            elif ch0 == '-':
                if state == ch0:
                    pass
                elif state == '+':
                    print(f'{diff_sep} file={file1}')
                    sep_printed = True
                    next_file = ''
                else:
                    print(f'{diff_start} file={file1}')
                    sep_printed = False
                    next_file = f' file={file2}'
                state = ch0
            elif ch0 == '+':
                if state == ch0:
                    pass
                elif state == '-':
                    print(f'{diff_sep} file={file2}')
                    sep_printed = True
                    next_file = ''
                else:
                    print(f'{diff_start} file={file2}')
                    sep_printed = False
                    next_file = f' file={file1}'
                state = ch0
            print(line[1:])
    
        if state:
            if not sep_printed:
                print(f'{diff_sep}{next_file}')
                next_file = ''
            print(diff_end)
    
        return 0
    
    if __name__ == '__main__':
        prog = os.path.basename(sys.argv[0])
        sys.exit(main())
    

    Aqui estão os arquivos de entrada com os quais eu testei. Eles são semelhantes, mas não exatamente iguais aos arquivos de entrada que postei originalmente na minha pergunta aqui ...

    ==== file.1====

    common line 1 ...
    common line 2 ...
    common line 3 ...
    something unique from file.1
    a second line of something unique from file.1
    common line 4 ...
    common line 5 ...
    something unique from file.1
    common line 6 ...
    common line 7 ...
    penultimate file.1 line
    common line 8 ...
    

    ==== file.2====

    common line 1 ...
    second line from file.2
    common line 2 ...
    common line 3 ...
    something unique from file.2
    common line 4 ...
    common line 5 ...
    something unique from file.2
    a second line of something unique from file.2
    common line 6 ...
    common line 7 ...
    common line 8 ...
    

    Eu executo o comando assim...

    filemerge file.1 file.2 >file.merged
    

    E estes são os conteúdos resultantes de file.merged...

    common line 1 ...
    <<<<<<<< file=file.2
    second line from file.2
    ======== file=file.1
    >>>>>>>>
    common line 2 ...
    common line 3 ...
    <<<<<<<< file=file.1
    something unique from file.1
    a second line of something unique from file.1
    ======== file=file.2
    something unique from file.2
    >>>>>>>>
    common line 4 ...
    common line 5 ...
    <<<<<<<< file=file.1
    something unique from file.1
    ======== file=file.2
    something unique from file.2
    a second line of something unique from file.2
    >>>>>>>>
    common line 6 ...
    common line 7 ...
    <<<<<<<< file=file.1
    penultimate file.1 line
    ======== file=file.2
    >>>>>>>>
    common line 8 ...
    

    Como mencionei, esse não é exatamente o mesmo formato da saída do "conflito de mesclagem" de git, mas é muito semelhante e está próximo o suficiente para mim.

    • 0

relate perguntas

  • Grep para um conjunto de linhas de $START a $END AND que contém uma correspondência em $MIDDLE

  • Reorganize as letras e compare duas palavras

  • Subtraindo a mesma coluna entre duas linhas no awk

  • Embaralhamento de arquivo de várias linhas

  • como posso alterar o caso do caractere (de baixo para cima e vice-versa)? ao mesmo tempo [duplicado]

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve