Другой способ замены новой строки вместо использования tr

Проблема может быть решена путем фильтрации вывода diff . Этот пример подходит мне (хотя размещение и размер желоба между левой и правой сторонами вывода diff, вероятно, будут деталями, которые различаются между реализациями):

#!/bin/sh
# $Id: diff-two-column,v 1.2 2016/09/26 20:38:32 tom Exp $
# see http://unix.stackexchange.com/questions/312025/how-to-associate-line-number-from-a-file-to-the-side-by-side-diff-output-result

usage() {
    cat >&2 <<EOF
usage: $0 file1 file2
EOF
    exit 1
}

[ $# = 2 ] || usage
[ -f "$1" ] || usage
[ -f "$2" ] || usage

width=${COLUMNS:-80}
check=$(stty size|cut -d' ' -f2)
[ -n "$check" ] && width=$check

diff -W $width -y "$1" "$2" | \
expand | \
awk -v width=$width '
BEGIN {
    L=0;
    R=0;
    gutter = width / 2;
    half = gutter - 2;
}
{
    textL = substr($0, 1, half - 1);
    sub("[ ]+$", "", textL);  # trim trailing blanks

    # The script relies on correctly extracting textM, the gutter:
    # if lines differ,    textM is " ! "
    # if line inserted,   textM is " > "
    # if line deleted,    textM is " < "
    # if lines unchanged, textM is "   "
    textM = substr($0, gutter - 2, 3);

    textR = ( length($0) > gutter ) ? substr($0, gutter+1, half) : "";

    if ( textM != " > " ) {
         L++;
    }
    if ( textM != " < " ) {
         R++;
    }

    if ( textL != textR ) {
        # printf "SHOW %s\n", $0;
        # printf "gap \"%s\"\n", textM;
        # printf "<<< \"%s\"\n", textL;
        # printf ">>> \"%s\"\n", textR;
        if ( textL == "" ) {
            printf "%5s %-*s %-3s %5d %s\n",
                " ", half, textL,
                textM,
                R, textR;
        } else if ( textR == "" ) {
            printf "%5d %-*s %-3s %5s %s\n",
                L, half, textL,
                textM,
                " ", textR;
        } else {
            printf "%5d %-*s %-3s %5d %s\n",
                L, half, textL,
                textM,
                R, textR;
        }
    } else {
        # printf "SKIP %s\n", $0;
    }
}
'

Вы не можете добавлять номера строк до diff , потому что, если есть вставки или удаления, номера строк, начинающиеся с этой точки, не будут совпадать, что делает различия бесполезными. Мой сценарий вычисляет номера строк для левой и правой сторон разницы в сценарии awk:

  • Сначала он решает, насколько широким будет разница, в зависимости от ширины терминала.
  • Есть (в GNU diff 3.2, которую я тестировал) желоб (неиспользуемое пространство) в середине параллельных различий. Начав с терминала с 80 столбцами, я нашел способ вычислить положение желоба.
  • После инициализации сценарий извлекает из каждой строки (в awk , это $ 0 ) левую ( textL ) и правую ( textR ) строк и проверяет, пусты ли они (что произошло бы, если бы была вставка / удаление).
  • Если левая и правая строки отличаются, сценарий восстанавливает вывод diff , но добавляет номера строк.

Учитывая, что это слева

1
2
3
4
This is line A
6
This is line C
123456789.123456789.123456789.123456789.123456789.

yyy

и это справа

1
2
3
4
This is line B
6
This is line D
abcdefghi.abcdefghi.abcdefghi.abcdefghi.abcdefghi.
xxx

(10 строк слева, 9 справа), этот сценарий выдаст

    5 This is line A                          |      5 This is line B
    7 This is line C                          |      7 This is line D
    8 123456789.123456789.123456789.1234567   |      8 abcdefghi.abcdefghi.abcdefghi.abcdefg
                                              |      9 xxx
   10 yyy                                     <        
3
01.05.2017, 04:55
3 ответа

Это будет работать даже без цикла для всех имен файлов, начинающихся с file:

perl -pe 's/\n/ /g' file*

Для таких операций я предпочитаю perl. Имеет тот же синтаксис, что и sed , является переносимым и не имеет всех этих странных параметров sed . Вы также можете применить переключатель -i к perl (например, sed), чтобы внести изменения на месте: perl -i.old -pe .... (старый файл будет скопирован с расширением .old -Вы можете просто использовать -i и файл резервной копии не будет сохранен)

Если вы предпочитаете, вы можете использовать команду find следующим образом:

$ find . -type f -name 'file*' -exec bash -c 'tr "\n" " " <$0 >$0.new' {} \;
2
27.01.2020, 21:21
perl -i -lpe '$\=$"' file.data

  • -i включает редактирование на месте.
  • -l устанавливает ORS = RS = "\n"
  • -p устанавливает неявное чтение входного файла + автоматическую печать записей.
  • $\ — это ORS, для которого установлено значение $" = OFS = пробел по умолчанию.
  • Конечно, вы можете дать команде perl несколько имен файлов. .
1
27.01.2020, 21:21

Это команда sed, которую вы ищете:

find /directory/. -type f -exec sed -i ':begin;$!N;s/\n/ /;tbegin' {} \;
0
27.01.2020, 21:21

Теги

Похожие вопросы