sed заменяет все символы табуляции и пробелы одним пробелом
Я получил строку вроде следующего:
test.de. 1547 IN SOA ns1.test.de. dnsmaster.test.de. 2012090701 900 1000 6000 600
теперь я хочу заменить все табуляции / пробелы между записями только одним пробелом, чтобы я мог легко использовать его с cut -d " "
Я попробовал следующее:
sed "s/[\t[:space:]]+/[:space:]/g"
и различные варианты, но не могли заставить его работать. Есть идеи?
3 ответа
Использование sed -e "s/[[:space:]]\+/ /g"
Вот объяснение:
[ # start of character class
[:space:] # The POSIX character class for whitespace characters. It's
# functionally identical to [ \t\r\n\v\f] which matches a space,
# tab, carriage return, newline, vertical tab, or form feed. See
# https://en.wikipedia.org/wiki/Regular_expression#POSIX_character_classes
] # end of character class
\+ # one or more of the previous item (anything matched in the brackets).
Для замены вам нужно только вставить пробел. [:space:]
не будет работать там, так как это аббревиатура для класса персонажа, а движок регулярных выражений не будет знать, какой символ поместить туда.
+
должен быть экранирован в регулярном выражении, потому что с двигателем регулярного выражения Сед +
это нормальный характер, тогда как \+
метасимвол для "один или несколько". На странице 86 " Освоение регулярных выражений" Джеффри Фридл упоминает в сноске, что ed и grep использовали экранированные скобки, потому что "Кен Томпсон считал, что регулярные выражения будут использоваться в основном для работы с кодом C, где необходимость сопоставления необработанных скобок будет более распространенной, чем обратная ссылка ". Я предполагаю, что он чувствовал то же самое по отношению к знаку плюс, отсюда и необходимость избегать его, чтобы использовать его в качестве метасимвола. Легко быть запутанным этим.
В седе вам нужно сбежать +
, ?
, |
, (
, а также )
, или используйте -r для использования расширенного регулярного выражения (тогда это выглядит как sed -r -e "s/[[:space:]]\+/ /g"
или же sed -re "s/[[:space:]]\+/ /g"
Вы можете использовать -s
("сжать") вариант tr
:
$ tr -s '[:blank:]' <<< 'test.de. 1547 IN SOA ns1.test.de. dnsmaster.test.de. 2012090701 900 1000 6000 600'
test.de. 1547 IN SOA ns1.test.de. dnsmaster.test.de. 2012090701 900 1000 6000 600
[:blank:]
класс символов включает в себя пробелы и символы табуляции.
Вот несколько интересных методов, которые я нашел в экспериментах (используя xxd для просмотра вкладок).
echo -e \\033c
s=$(echo -e "a\t\tb\t\tc\t\td\t\te\tf")
echo 'original string with tabs:'
echo "$s"
echo "$s" | xxd
echo -e '\nusing: \techo "$s" | tr -s \\\\t " "'
echo "$s" | tr -s \\t " "
echo "$s" | tr -s \\t " " | xxd
echo -e '\nusing: \techo "$s" | sed '"'s/\\\\t/ /g'"
echo "$s" | sed 's/\t\+/ /g'
echo "$s" | sed 's/\t\+/ /g' | xxd
echo -e '\nusing: \techo ${s/ / }'
echo ${s/ / }
echo ${s/ / } | xxd
z=$(echo $s)
echo -e '\nusing: \tz=$(echo $s); echo "$z"'
echo "$z"
echo "$z" | xxd
echo -e '\nusing: \tread s < file.in; echo $s'
read s < file.in
echo $s
echo $s | xxd
echo -e '\nusing: \twhile read s; do echo $s; done'
while read s;
do
echo $s
done < file.in
Мне нравится использовать следующий псевдоним для Bash. Основываясь на том, что написали другие, используйте sed для поиска и замены нескольких пробелов одним пробелом. Это помогает получить последовательные результаты от резки. В конце я запускаю его через sed еще раз, чтобы изменить пространство на табуляцию, чтобы его было легче читать.
alias ll='ls -lh | sed "s/ \+/ /g" | cut -f5,9 -d" " | sed "s/ /\t/g"'