Учитывая файл input.csv, как показано ниже,
EMP_ID,EMP_NAME,JOINING_DATE,SALARY
1,T Natarajan,22-APR-2024,6000000
2,Velmurugan,22-JUL-2024,2000000
3,Rowin,21-OCT-2024,5000000
#END_OF_FILE
как добавить префикс «E_» ко всем строкам, кроме первой строки и строк, начинающихся с символа решетки (#). Ожидаемый результат:
EMP_ID,EMP_NAME,JOINING_DATE,SALARY
E_1,T Natarajan,22-APR-2024,6000000
E_2,Velmurugan,22-JUL-2024,2000000
E_3,Rowin,21-OCT-2024,5000000
#END_OF_FILE
Пробовал эту команду sed -i -E '/^(#)/! s/^/E_/' input.csv
, но она также обновляет 1-ю строку.
Вы ничего не делаете, чтобы исключить первую строку.
С помощью фигурных скобок можно объединить два условия:
sed '/^#/!{;1!s/^/E_/;}' input.csv
или возможно
sed '2,${;/^#/!s/^/E_/;}' input.csv
или вы можете изменить логику, чтобы пропустить эти строки;
sed '/^#/b;1b;s/^/E_/' input.csv
(Команда b
говорит «перейти к этой точке сценария»; без метки она переходит к концу, пропуская остальную часть сценария для текущей строки ввода.)
Я убрал опцию -i
; верните его, как только убедитесь, что результаты соответствуют вашим ожиданиям.
Кроме того, круглые скобки ничего не значили, поэтому я их тоже удалил. При этом скрипт больше не использует синтаксис ERE, поэтому я также удалил опцию -E
.
Точки с запятой рядом с фигурными скобками необязательны в некоторых диалектах, но, вероятно, необходимы в других.
Если вы хотите сделать это в Awk, это должно быть легко.
awk 'FNR > 1 && !/^#/ { sub(/^/, "E_") } 1' file >newfile
В стандартном Awk нет такой опции, как опция -i
в (нестандартном) sed
; но GNU Awk предлагает -i inplace
Вы также можете использовать awk в качестве решения
awk 'NR > 1 && !/^#/ {$0 = "E_" $0} "true"' input.csv
Объяснение:
NR > 1
означает выполнение, начиная со второй строки
А «истина» означает отображение всех строк.
!/^#/
: проверяет, не начинается ли строка с #
. Если строка начинается с хеша, это условие будет ложным и префикс не будет добавлен.
Действительно, любая непустая строка или 0 считаются истинными.
Вы можете использовать awk
для печати всей строки, если это не первая строка или она начинается с #
.
В противном случае вы печатаете всю строку, перед которой стоит E_
.
awk 'NR==1 || /^#/ {print; next} {print "E_" $0}' input.csv
Выход
E_EMP_ID,EMP_NAME,JOINING_DATE,SALARY
E_1,T Natarajan,22-APR-2024,6000000
E_2,Velmurugan,22-JUL-2024,2000000
E_3,Rowin,21-OCT-2024,5000000
#END_OF_FILE
!NF
пропускает пустые строки, а не первую.
@tripleee Да, вы правы, так должно быть !NR
, но я изменил его на NR==0
, чтобы было понятнее.
Это все еще неверно; в первой строке есть NR==1
. Но теперь я обновил свой ответ решением Awk.
@tripleee Теперь все должно быть в порядке, ваш awk с сабвуфером тоже очень хорош.
Это может сработать для вас (GNU sed):
sed '1!s/^[^#]/E_&/' file
Если это не первая строка и не начинается с символа #
, вставьте E_
в начале строки.
Я попробовал это с другим подходом, однако он работает только с предоставленными строками.
sed -i -e 's/^/E_/' -e '1s/E_//' -e 's/E_#/#/' file
Добавление чего-либо повсюду, а затем удаление этого при определенных условиях всегда является худшим (менее понятным и/или более хрупким и/или менее эффективным) подходом, чем простое добавление чего-либо при определенных условиях. В этом случае, если первая строка ввода начиналась с E_#7
, то 's/^/E_/'
изменило бы ее на E_E_#7
, затем '1s/E_//'
изменило бы ее обратно на E_#7
, а затем 's/E_#/#/'
изменило бы ее на #7
, тем самым испортив ее. Вы сказали: «Однако это работает только с предоставленными строками». - очевидно, что публиковать скрипт, который работает только с определенным набором входных данных, бесполезно.
Используя любой awk:
$ awk '{print (NR==1 || /^#/ ? "" : "E_") $0}' file
EMP_ID,EMP_NAME,JOINING_DATE,SALARY
E_1,T Natarajan,22-APR-2024,6000000
E_2,Velmurugan,22-JUL-2024,2000000
E_3,Rowin,21-OCT-2024,5000000
#END_OF_FILE
"true"
, конечно, тоже подойдет, но общепринятая идиома — просто1
. Но это не учитывает требование заменять только те строки, которые не начинаются с#
.