Как заменить пробелы и косую черту в строке в bash?
дав строку:
foo='Hello
World!
x
we are friends
here we are'
Supose есть также символы смешивается с пробелами после или до символ.
Я хочу заменить пробелы, вкладки и косую черту только пробелом. Я попробовал с:
echo "$foo" | tr "[st]\[st]n[st]" " " | tr -s " "
возвращает:
Hello World! x we are friend here we are
и результат мне нужен:
Hello World! x
we are friends
here we are
какая-то идея, совет или трюк, чтобы сделать это? Могу ли я получить желаемый результат только в команде?
9 ответов
следующая острота дает желаемый результат:
echo "$foo" | tr '\n' '\r' | sed 's,\s*\\s*, ,g' | tr '\r' '\n'
Hello World!
we are friends
here we are
объяснение:
tr '\n' '\r'
удаляет новые строки из входных данных, чтобы избежать специального поведения sed для новых строк.
sed 's,\s*\\s*, ,g'
преобразует пробелы со встроенным \ в одно пространство.
tr '\r' '\n'
кладет неизменной строк.
если вы просто хотите вывести на печать, и вам просто нужно:
foo='Hello \
World!'
bar=$(tr -d '\' <<<"$foo")
echo $bar # unquoted!
Hello World!
если вы хотите сжать пробелы, поскольку они хранятся в переменной, то один из:
bar=$(tr -d '\' <<<"$foo" | tr -s '[:space:]' " ")
bar=$(perl -0777 -pe 's/\$//mg; s/\s+/ /g' <<<"$foo")
преимущество версии perl заключается в том, что она удаляет только обратные косые черты продолжения строки (в конце строки).
обратите внимание, что при использовании двойных кавычек оболочка заботится о продолжениях строк (правильные без пробелов после Слэш:
$ foo="Hello \
World"
$ echo "$foo"
Hello World
Итак, на данный момент уже слишком поздно.
если вы используете одинарные кавычки, оболочка не будет интерпретировать продолжения строк и
$ foo='Hello \
World!
here we are'
$ echo "$foo"
Hello \
World!
here we are
$ echo "$foo" | perl -0777 -pe 's/(\s*\\s*\n\s*)/ /sg'
Hello World!
here we are
foo='Hello \
World! \
x
we are friends
here we are'
если вы используете двойные кавычки, то оболочка будет интерпретировать \
как символ продолжения строки. Переключение на одинарные кавычки сохраняет обратную косую черту литерала.
я добавил обратную косую черту после World!
для проверки нескольких строк обратной косой черты в строке.
sed -r ':s; s/( )? *\ *$//; Te; N; bs; :e; s/\n *//g' <<< "$foo"
выход:
Hello World! x
we are friends
here we are
что это делаешь? В псевдо-коде вы можете прочитать это как:
while (s/( )? *\ *$//) { # While there's a backslash to remove, remove it...
N # ...and concatenate the next line.
}
s/\n *//g # Remove all the newlines.
подробно, вот что это делает:
-
:s
это ветка с надписьюs
для "start". -
s/( )? *\ *$//
заменяет обратную косую черту и окружающие ее пробелы. Он оставляет одно пространство, если оно было, захватив( )?
. - если предыдущая подстановка не удалась,
Te
переход на меткуe
. -
N
объединяет следующую строку, включая новую строку\n
. -
bs
возвращается к началу. Это чтобы мы могли справиться. несколько последовательных строк с обратными косыми чертами. -
:e
это ветка с надписьюe
для "end". -
s/\n *//g
удаляет все дополнительные новые строки из шага #4. Он также удаляет ведущие пробелы из следующей строки.
отметим, что T
является расширением GNU. Если вам нужно это для работы в другой версии sed, вам нужно использовать . Это, вероятно, займет дополнительное b
метка или два.
можно использовать read
петли, чтобы получить желаемый результат.
arr=()
i=0
while read line; do
((i++))
[ $i -le 3 ] && arr+=($line)
if [ $i -eq 3 ]; then
echo ${arr[@]}
elif [ $i -gt 3 ]; then
echo $line
fi
done <<< "$foo"
С awk
:
$ echo "$foo"
Hello \
World! \
x
we are friends
here we are
С трейлингом newline:
$ echo "$foo" | awk '{gsub(/[[:space:]]*\[[:space:]]*/," ",)}1' RS= FS='\n' ORS='\n\n'
Hello World! x
we are friends
here we are
.
без трейлинга newline:
$ echo "$foo" |
awk '{
gsub(/[[:space:]]*\[[:space:]]*/," ",)
a[++i] =
}
END {
for(;j<i;) printf "%s%s", a[++j], (ORS = (j < NR) ? "\n\n" : "\n")
}' RS= FS='\n'
Hello World! x
we are friends
here we are
sed-отличный инструмент для простых подмножеств на одной строке, но для чего-либо еще просто используйте awk. Это использует GNU awk для multi-char RS (с другими awks RS=''
будет работать для текстовых файлов, которые не содержат нуль символов):
$ echo "$foo" | awk -v RS='^$' -v ORS= '{gsub(/\s+\\s+/," ")}1'
Hello World! x
we are friends
here we are
С башизмами, такими как расширенные подстановка, расширения параметр etc...но это, вероятно, так же уродливо
foo='Hello \
World!'
shopt -s extglob
echo "${foo/+( )\*( )$'\n'/ }"
Hello World!
Как я понимаю, вы хотите просто удалить конечные пробелы, за которыми следует новая строка с обратной косой чертой?
в этом случае выполните поиск с помощью regex ( ) *\\n
и заменить на