Имя файла нужно заключить в кавычки:
touch "directory/file with whitespace (and special characters)"
Пожалуйста, прочитайте о кавычках и специальных символах в руководстве bash.
Использованиеawk
:
$ awk -v RS='' -v ORS='\n\n' 'match($0,".*TMP") { print substr($0,1,RLENGTH) }' file
GFD
DFC
VGF
HGD
TMP
TFD
PI1
98A
TMP
TMP
Это рассматривает набор строк, разделенных хотя бы одной пустой строкой, как запись. Если запись соответствует регулярному выражению .*TMP
, бит после совпадения удаляется, а остальная часть записи печатается.
Бит после последнего вхождения TMP
удаляется путем сопоставления регулярного выражения .*TMP
с текущей записью, а затем использования substr()
для вывода только бита, соответствующего этому выражению. Регулярное выражение будет соответствовать от начала записи до последнего TMP
в ней, а функция match()
устанавливает для переменной RLENGTH
длину этого совпадения.
Вы получите дополнительную пустую строку в конце вывода, так как мы используем двойную новую строку в качестве разделителя выходных записей.
Если вместо этого ваш файл выглядит как
AAA
CBH
VFh
GFD
DFC
VGF
HGD
tmp/some/path/here
JHG
TFD
PI1
98A
tmp/some/path/here
tmp/some/path/here
765
UBS
... и вы хотели бы сделать такое же преобразование на основе строк, начинающихся с tmp
, а затем изменить регулярное выражение, используемое с match()
в команде, чтобы оно полностью соответствовало символ новой строки в конце «tmp
- строки»:
$ awk -v RS='' -v ORS='\n\n' 'match($0,".*tmp[^\n]*") { print substr($0,1,RLENGTH) }' file
GFD
DFC
VGF
HGD
tmp/some/path/here
TFD
PI1
98A
tmp/some/path/here
tmp/some/path/here
Обратите внимание, что я не уверен на 100%, как awk
должен интерпретировать \n
внутри выражения в квадратных скобках, но все awk
реализации, к которым у меня есть доступ (OpenBSD awk
, mawk
,и GNE awk
), кажется, рассматривает is как новую строку, а не как два отдельных символа \
и n
.
Просто инвертируйте текст и выполните обычную печать от регулярного выражения к регулярному выражению, а затем снова -инвертируйте, чтобы получить исходный порядок
tac < file.txt | sed -n '/TMP/,/^$/p' | tac
Если вы согласны с первым TMP
. Пустой RS
приведет к режиму абзаца, где два или более последовательных символа \n
будут использоваться в качестве разделителя записи
$ # sub is used to remove everything after first occurrence of TMP
$ # return value of sub (0 if no match, 1 if match is found) determines
$ # if record should be printed or not
$ # use \nTMP\n to match only whole line
$ awk -v RS= 'sub(/TMP\n.*/, "TMP\n")' ip.txt
GFD
DFC
VGF
HGD
TMP
TFD
PI1
98A
TMP
Если вам нужно до конца TMP
, вы можете сделать это с помощьюGNU awk
(из-заgensub
)илиperl
$ # use \nTMP\n to match only whole line
$ # same as: perl -00 -ne 'print if s/.*TMP\n\K.*/\n/s' ip.txt
$ awk -v RS= '/TMP/{print gensub(/(.*TMP\n).*/, "\\1", 1)}' ip.txt
GFD
DFC
VGF
HGD
TMP
TFD
PI1
98A
TMP
TMP
Вы пометили sed, поэтому мы можем сделать это, как показано. Обратите внимание, что мы используем GNU sed. Насколько я понимаю, вы хотите удалить все после последней строки, начинающейся с tmp (в нижнем регистре )в каждом абзаце текстового файла. Абзац — это остров из непустой строки (и ), отделенный хотя бы одной пустой строкой от следующего экземпляра.
sed -e '
/./{H;$!d;}
x;/\ntmp/!d
:chop
/\ntmp[^\n]*$/!s/\n[^\n]*$//
t chop
' file
Накопить абзац в удержании. Когда мы наталкиваемся на границу (пустой строки или конец ), мы начинаем исследовать параграф. Если в начале новой строки не видно tmp, мы сразу же удаляем этот параграф. В противном случае мы начинаем обрезать строки с конца параграфа, пока не увидим строку tmp. Остановите обработку этого параграфа и распечатайте его.
В GNU awk мы работаем в режиме абзаца и устанавливаем входное поле разделитель на новую строку. Начинайте рассматривать поля с конца. Как только мы увидим поле, начинающееся с tmp Мы уменьшаем параграф до этого поля и печатаем и покончим с этим абзацем.
awk -F '\n' -v RS= -v OFS='\n' '
/(^|\n)tmp/ {
for(i=NF; i; i--) {
if ($i ~ /^tmp/) {
NF=i; NF++; print; break
}
}
}
' file
rindex сообщит позицию подстроки в строке с конца. Так что получите позицию последнего tmp с помощью rindex abd и используйте эту позицию, чтобы получить позицию следующей ближайшей новой строки справа.
perl -p00e '
s/.*//s,next unless /^tmp/m;
s/\z/\n/;
my $p = 1+rindex($_, "\ntmp");
my $q = 1+index($_, "\n", $p);
substr($_, $q) = "\n";
' file