sed - удалите самое последнее возникновение строки (запятая) в файле?

Хотя процесс, используемый для нахождения его, заставил бы Вас думать, что это, это не на самом деле репозиторий, это - на самом деле просто простая доля файла. В этой ситуации Ваш лучший выбор состоял бы в том, чтобы удалить все Ваши обеспеченные openSUSE моно пакеты (комната застежки-молнии), заблокировать их (застегните al), и установка (застежка-молния в) пакеты от доли файла монопроекта.

С другой стороны, моно на Фабрике OpenSUSE теперь в следующей основной версии (3.0.2), таким образом, Вы могли также получить свои пакеты оттуда. Хотя, я рекомендовал бы не сделать - Фабрика не подходит для ежедневного использования, и существует возможность, которую пакеты от Фабрики могут вытянуть в других несовместимых пакетах и вызвать серьезные проблемы.

15
26.04.2015, 19:36
7 ответов

Использование awk

Если запятая всегда находится в конце второго до последней строки:

$ awk 'NR>2{print a;} {a=b; b=$0} END{sub(/,$/, "", a); print a;print b;}'  input
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]

с использованием awk и Bash

$ awk -v "line=$(($(wc -l <input)-1))" 'NR==line{sub(/,$/, "")} 1'  input
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]

с использованием SED

$ sed 'x;${s/,$//;p;x;};1d'  input
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]

Для платформ OSX и других BSD попробуйте:

sed -e x -e '$ {s/,$//;p;x;}' -e 1d  input

Использование Bash

while IFS=  read -r line
do
    [ "$a" ] && printf "%s\n" "$a"
    a=$b
    b=$line
done <input
printf "%s\n" "${a%,}"
printf "%s\n" "$b"
12
27.01.2020, 19:49

Просто попробуйте нижеприведенную команду Perl на один лайнер.

perl -00pe 's/,(?!.*,)//s' file

Объяснение:

  • , Совпадает с запятой.
  • (?!*,) Отрицательный взгляд утверждает, что после этой совпавшей запятой не будет запятой. Так что она совпадает с последней запятой.
  • s И наиболее импортирующим является модификатор s DOTALL, который делает точку, чтобы соответствовать даже символам новой строки.
4
27.01.2020, 19:49

Если вы можете использовать TAC :

tac file | perl -pe '$_=reverse;!$done && s/,// && $done++;$_=reverse'|tac
2
27.01.2020, 19:49

Если запятая не может быть на второй к последней строке

, используя awk и TAC :

tac foo.csv | awk '/,$/ && !handled { sub(/,$/, ""); handled++ } {print}' | tac

Команда awk простой, чтобы сделать замену Первый раз узор видно. TAC меняет порядок строк в файле, Таким образом, команда awk заканчивается удалением последнего запятой.

Мне сказали, что

tac foo.csv | awk '/,$/ && !handled { sub(/,$/, ""); handled++ } {print}' > tmp && tac tmp

может быть более эффективным.

2
27.01.2020, 19:49

См. https://stackoverflow.com/questions/12390134/remove-comma-from-last-line

Это работает для меня:

$cat input.txt
{"name": "secondary_ua","type":"STRING"},
{"name": "request_ip","type":"STRING"},
{"name": "cb","type":"STRING"},
$ sed '$s/,$//' < input.txt >output.txt
$cat output.txt
{"name": "secondary_ua","type":"STRING"},
{"name": "request_ip","type":"STRING"},
{"name": "cb","type":"STRING"}

Мои лучше Способ удалить последнюю строку и после удаления запятой, добавьте] CHAR снова

1
27.01.2020, 19:49
lcomma() { sed '
    $x;$G;/\(.*\),/!H;//!{$!d
};  $!x;$s//\1/;s/^\n//'
}

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

Когда он встречает запятую, он меняет местами текущий буфер строки с буфером удержания и таким образом одновременно распечатывает все строки, которые произошли с момента последней запятой , а освобождает буфер удержания.

Я просто копался в своем файле истории и нашел следующее:

lmatch(){ set "USAGE:\
        lmatch /BRE [-(((s|-sub) BRE)|(r|-ref)) REPL [-(f|-flag) FLAG]*]*
"       "${1%"${1#?}"}" "$@"
        eval "${ZSH_VERSION:+emulate sh}"; eval '
        sed "   1x;     \\$3$2!{1!H;\$!d
                };      \\$3$2{x;1!p;\$!d;x
                };      \\$3$2!x;\\$3$2!b'"
        $(      unset h;i=3 p=:-:shfr e='\033[' m=$(($#+1)) f=OPTERR
                [ -t 2 ] && f=$e\2K$e'1;41;17m}\r${h-'$f$e\0m
                f='\${$m?"\"${h-'$f':\t\${$i$e\n}\$1\""}\\c' e=} _o=
                o(){    IFS=\ ;getopts  $p a "$1"       &&
                        [ -n "${a#[?:]}" ]              &&
                        o=${a#-}${OPTARG-${1#-?}}       ||
                        ! eval "o=$f;o=\${o%%*\{$m\}*}"
        };      a(){    case ${a#[!-]}$o in (?|-*) a=;;esac; o=
                        set $* "${3-$2$}{$((i+=!${#a}))${a:+#-?}}"\
                                ${3+$2 "{$((i+=1))$e"} $2
                        IFS=$;  _o=${_o%"${3+$_o} "*}$*\
        };      while   eval "o \"\${$((i+=(OPTIND=1)))}\""
                do      case            ${o#[!$a]}      in
                        (s*|ub)         a s 2 ''        ;;
                        (r*|ef)         a s 2           ;;
                        (f*|lag)        a               ;;
                        (h*|elp)        h= o; break     ;;
                esac;   done;   set -f; printf  "\t%b\n\t" $o $_o
)\"";}

Это действительно неплохо. Да, он использует eval , но никогда не передает ему ничего, кроме числовой ссылки на его аргументы. Он создает произвольные сценарии sed для обработки последнего совпадения. Я покажу вам:

printf "%d\" %d' %d\" %d'\n" $(seq 5 5 200) |                               
    tee /dev/fd/2 |                                                         
    lmatch  d^.0     \  #all re's delimit w/ d now                           
        -r '&&&&'    \  #-r or --ref like: '...s//$ref/...'      
        --sub \' sq  \  #-s or --sub like: '...s/$arg1/$arg2/...'
        --flag 4     \  #-f or --flag appended to last -r or -s
        -s\" \\dq    \  #short opts can be '-s $arg1 $arg2' or '-r$arg1'
        -fg             #tacked on so: '...s/"/dq/g...'                     

Это выводит на stderr следующее. Это копия ввода lmatch :

5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
105" 110' 115" 120'
125" 130' 135" 140'
145" 150' 155" 160'
165" 170' 175" 180'
185" 190' 195" 200'

Подоболочка функции eval ed выполняет итерацию по всем своим аргументам один раз. Обходя их, он соответствующим образом выполняет итерацию счетчика в зависимости от контекста для каждого переключателя и пропускает такое количество аргументов для следующей итерации. С этого момента он выполняет одно из следующих действий для каждого аргумента:

  • Для каждой опции синтаксический анализатор добавляет $ a к $ o . $ a назначается на основе значения $ i , которое увеличивается на счетчик аргументов для каждого обработанного аргумента. $ a присваивается одно из двух следующих значений:
    • a = $ ((i + = 1)) - это присваивается, если какой-либо из коротких параметров не к нему добавлен аргумент или если вариант был длинным.
    • a = $ i # -? - назначается, если параметр короткий и имеет ли аргумент , добавленный к нему.
    • a = \ $ {$ a} $ {1: + $ d \ $ {$ (($ 1)) \}} - Независимо от начального назначения, $ a 's значение всегда заключено в фигурные скобки и - в случае -s - иногда $ i увеличивается еще на одно и добавляется дополнительное поле с разделителями.

В результате eval никогда не передается строка, содержащая какие-либо неизвестные. На каждый из аргументов командной строки ссылаются по их числовому номеру аргумента - даже по разделителю, который извлекается из первого символа первого аргумента и является единственным случаем, когда вы должны использовать любой неэкранированный символ. По сути, функция является генератором макросов - она ​​никогда не интерпретирует значения аргументов каким-либо особым образом, потому что sed может (и, конечно же) легко справится с этим при синтаксическом анализе скрипта. . Вместо этого он просто разумно упорядочивает свои аргументы в работоспособный скрипт.

Вот некоторые отладочные результаты работы функции:

... sed "   1x;\\$2$1!{1!H;\$!d
        };      \\$2$1{x;1!p;\$!d;x
        };      \\$2$1!x;\\$2$1!b
        s$1$1${4}$1
        s$1${6}$1${7}$1${9}
        s$1${10#-?}$1${11}$1${12#-?}
        "
++ sed '        1x;\d^.0d!{1!H;$!d
        };      \d^.0d{x;1!p;$!d;x
        };      \d^.0d!x;\d^.0d!b
        sdd&&&&d
        sd'\''dsqd4
        sd"d\dqdg
        '

Итак, lmatch можно использовать для простого применения регулярных выражений к данным, следующим за последним совпадением в файле. Результат выполнения команды, которую я выполнил выше:

5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
101010105dq 110' 115dq 120'
125dq 130' 135dq 140sq
145dq 150' 155dq 160'
165dq 170' 175dq 180'
185dq 190' 195dq 200'

... который, учитывая подмножество файлового ввода, следующего за последним совпадением / ^. 0 / , применяет следующие подстановки:

  • sdd &&&& d - заменяет $ match на себя 4 раза.
  • sd'dsqd4 - четвертая одинарная кавычка после начала строки после последнего совпадения.
  • sd "d \ dqd2 - то же самое, но для двойных кавычек и глобально.

Итак, чтобы продемонстрировать, как можно использовать lmatch для удаления последней запятой в файле:

printf "%d, %d %d, %d\n" $(seq 5 5 100) |
lmatch '/\(.*\),' -r\\1

ВЫВОД:

5, 10 15, 20
25, 30 35, 40
45, 50 55, 60
65, 70 75, 80
85, 90 95 100
4
27.01.2020, 19:49

Попробуйте выполнить следующую команду sed.

sed -i '$s/,$//' foo.csv
-1
27.01.2020, 19:49

Теги

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