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


14

У меня есть файл

xyz... rsync: "/home/path/to/file": Permission denied (13) rsync:
"/home/path/to/file1": Permission denied (13) rsync:
"/home/path/to/file2": Permission denied (13) rsync:
"/home/path/to/file3": Permission denied (13)

Теперь я хочу извлечь только пути к файлам и сохранить их в другом файле. Выходной файл выглядит так:

/home/path/to/file 
/home/path/to/file1 
/home/path/to/file2
/home/path/to/file3

Используя sed или awk, как я могу это сделать?

Я пытался, sed -n '/"/,/"/p' myfileно это не работает.


3
Для тех, кто голосует, чтобы закрыть - Как это может быть не по теме? Речь идет о программировании оболочки! Это ПРОГРАММИРОВАНИЕ, которое находится в теме для переполнения стека!
Джонатан Леффлер

2
Добро пожаловать в переполнение стека. Как вы можете видеть, у нас иногда возникают проблемы с людьми, у которых зудящие спусковые пальцы закрывают совершенно хорошие вопросы (такие как этот) с плохими причинами закрытия. Это случается не так часто (или я не вижу проблемы во времени так часто), но это случается. Не забудьте прочитать часто задаваемые вопросы .
Джонатан Леффлер

Ответы:


17

Вы можете передать stderr вашей команды rsync в скрипт awk:

awk -F '"' '{print $2}' 

Или к команде сокращения как это:

cut -d'"' -f2

2
Или, короче:cut -d\" -f2

@AndersJohansson: Спасибо, я также добавил вашу команду вырезания, чтобы ответить.
анубхава

Я думаю, что это не будет работать .. как вы можете видеть, что номер поля пути к файлу не является фиксированным $ 2 или f2 .. Спасибо!

На самом деле rsync всегда будет писать filepath первым между "и "на stderr.
анубхава

1
@ Jam88: На самом деле, это будет работать из-за того, как Ануббхава написал это. Разделитель поля установлен в двойную кавычку. Это означает, что все до первой двойной кавычки (возможно, пустой строки) есть $1; все между первой и второй двойными кавычками есть $2; и все после второй двойной кавычки находится в $3( $4, ...). Имя файла (по-видимому) всегда между первыми двумя двойными кавычками, поэтому это решение должно работать (и работало, когда я его проверял).
Джонатан Леффлер

6

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

sed 's/^[^"]*"\([^"]*\)".*/\1/'

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

$ sed 's/^[^"]*"\([^"]*\)".*/\1/' <<'EOF'
> xyz... rsync: "/home/path/to/file": Permission denied (13) rsync:
> "/home/path/to/file1": Permission denied (13) rsync:
> "/home/path/to/file2": Permission denied (13) rsync:
> "/home/path/to/file3": Permission denied (13)
> EOF
/home/path/to/file
/home/path/to/file1
/home/path/to/file2
/home/path/to/file3
$

Протестируйте RHEL 5 Linux с GNU sed, но только с использованием функций, которые работали бы в 7-й версии UNIX ™ sed.

Кстати, немного более простой способ сделать это с помощью двух замещающих команд; изменить все, вплоть до первой двойной кавычки, включая пустую строку (это последовательность из нуля или более не кавычек, за которыми следует двойная кавычка); измените все после того, что сейчас является первой двойной кавычкой, на ничто:

sed 's/^[^"]*"//; s/".*//'

Кстати, команда, которую вы пробовали (`sed -n '/" /, / "/ p'), печатает из одной строки, содержащей двойные кавычки, в следующую строку, содержащую двойные кавычки, без редактирования строк вообще. Вот почему, похоже, это не сработало для вас - оно сделало то, что вы просили, но то, что вы просили сделать, было не тем, что вы намеревались просить это сделать.

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


1

Если ваша версия grepподдерживает Perl-regexp:

grep -oP '(?<=")/home/.*?(?=")' file >> anotherfile

Результаты:

/home/path/to/file
/home/path/to/file1
/home/path/to/file2
/home/path/to/file3

Вы также можете сделать это менее строгим, чтобы соответствовать чему-либо между двойными, если вы хотите:

grep -oP '(?<=")[^"]*' file >> anotherfile

Вам нужно сделать .*не-жадным с .*?на тот случай, если позже в строке появятся дополнительные двойные кавычки? Или использовать [^"]*вместо .*?
Джонатан Леффлер

-1

Используйте оператор >>, чтобы сохранить любой вывод в файл.

подобно

grep -r "pattern" * >> file.txt

Так что просто измените это для вашего конкретного сценария, используя sed, добавив

>> filename

в команду


grep -rДелает рекурсивный поиск с помощью любых каталогов , перечисленных в аргументах ( *). Непонятно, какой шаблон вы имеете в виду, но grepподхватите всю линию. Цель упражнения - собрать информацию из части строки. Если вы используете GNU grep, есть способы сделать это ( -o); они нестандартны (за исключением того, что GNU определяет стандарт де-факто). Аналогично с использованием регулярных выражений PCRE; это еще одно расширение GNU. Они хороши, если у вас есть GNU grepи вы не планируете работать на платформах, где GNU grepпо умолчанию недоступна.
Джонатан Леффлер

Извините, что пропустил это, я думал, что он хотел знать в целом, что нужно сделать, чтобы поместить вывод в файл, и grep был просто примером.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.