Как «удалить» / удалить символы перед строкой?

12

У меня есть строка, которой я хотел бы манипулировать. Строка, H08W2345678как бы я мог манипулировать ею, чтобы вывод был просто W2345678?

Точно так же, если бы я хотел отбросить последние 4 символа, H08W2345678чтобы я получил, H08W234как бы я это сделал?

3kstc
источник
1
Есть много способов манипулировать строками. Есть ли конкретная причина для использования sed?
don_crissti
@don_crissti Нет причин, кроме отсутствия опыта. Любые альтернативы приветствуются ...
3kstc
@don_crissti, история: из отфильтрованного файла CSV я беру один из параметров из строки, которая является H08W2345678и должна манипулировать им, чтобы W2345678Это значение с другими данными было помещено в отправленное электронное письмо. Отправка электронной почты будет осуществляться с помощью cron.
3kstc
@don_crissti awkэто. Я создаю массив, а затем изменяю каждый элемент в массиве (все по-разному - т.е. меняем метку времени эпохи в секундах на дату и т. Д.)
3kstc
2
Вы можете делать такие вещи с помощью awk:printf %s\\n "XX,H08W2345678,YY" | awk -F, '{print substr($2, 4); print substr($2, 1, length($2)-4)}'
don_crissti

Ответы:

18

Просто используя bash (или ksh93откуда этот синтаксис или zsh):

string="H08W2345678"

echo "${string:3}"
W2345678

echo "${string:0:-4}"
H08W234

См. Wooledge wiki для более подробной информации о манипуляции со строками .

jasonwryan
источник
Для этого требуется bash 4.2 или выше. См. Эту старую копию справочного руководства Bash, раздел 3.5.3, «Расширение параметров оболочки» или ответ цыплят здесь, чтобы увидеть старое ограничение (« длина должна быть равна числу, большему или равному нулю».); … (Продолжение)
Скотт
(Продолжение)… см. Изменения в Bash (на вики Bash Hackers) (прокрутите вниз до конца раздела) или новости bash в организации службы технической инфраструктуры в Case Western Reserve University (поиск «добавлен в bash-4.2») а затем прокрутите вниз до «q.», чтобы увидеть ревизию. …………  "${string:0:${#string}-4}" Работает в bash версии 4.1, если длина $stringне менее 4.
Скотт
PS Это также душит строки вроде abc-e, где, когда вы отбрасываете первые три символа, у вас остается -e(потому echo -eчто не делает то, что вы хотели).
Скотт
8
$ echo "H08W2345678" | sed 's/^.\{3\}//'
W2345678

sed 's/^.\{3\}//'найдет первые три символа ^.\{3\}и заменит их пробелом. Здесь ^.будет соответствовать любой символ в начале строки ( ^указывает на начало строки) и \{3\}будет соответствовать предыдущему шаблону ровно 3 раза. Итак, ^.\{3\}подойдут первые три символа.

$ echo "H08W2345678" | sed 's/.\{4\}$//'
H08W234

Точно так sed 's/.\{4\}$//'же заменит последние четыре символа на пустые ( $указывает на конец строки).

heemayl
источник
1
Не могли бы вы объяснить, 's/^.\{3\}//'и 's/.\{4\}$//'как я все еще учусь sed, большое спасибо
3kstc
@ 3kstc: Пожалуйста, проверьте правки
Heemayl
1
За несколько символов, я хотел бы использовать ...вместо .\{3\}так (для меня) это легче читать: sed -e 's/^...//' -e 's/....$//' или в одном выражении с чередованием: sed -r 's/^...|....$//g'. Если бы это было больше, чем несколько символов, то я бы использовал /.\{17}\/выражение вместо /.............../.
Джонни
Это будет вести себя плохо, если строка -eили -n. Конечно, смысл «падение последних 4 -х символов» не определено для строки короче 4 -х символов, но, если кто - то хотел , чтобы приспособить это бросить первый или последний один символ, это может взорвать.
Скотт
2

Если у вас есть файл, в котором каждая строка представляет собой одиннадцатизначную (или любую другую) строку, которую вы хотите разделить, sedэто инструмент для использования. Это хорошо для манипулирования одной строкой, но это излишне. Для одной строки ответ Джейсона, вероятно, будет лучшим, если у вас есть доступ к bash версии 4.2 или выше. Тем не менее, и Синтаксисы кажутся уникальными для Баш (ну, баш, ksh93, МКШ, и ЗШ) - я не вижу их в The Open Group Base спецификации для Shell Command Language . Если вы застряли в POSIX-совместимой оболочке, которая не поддерживает расширение подстроки (извлечение), вы можете использовать${parameter:offset}${parameter:offset:length}

$ printf "%s\n" "${string#???}"
W2345678

$ printf "%s\n" "${string%????}"
H08W234

используется printfвместо echoдля защиты от таких строк, как abc-e, например , где, когда вы отбрасываете первые три символа, вы остаетесь с -eecho -eне делаете то, что хотели бы).

И, если вы вообще не используете оболочку семейства Bourne (или используете древнюю систему, предшествующую POSIX), они все равно должны работать:

$ expr " $string" : ' ...\(.*\)'
W2345678

$ expr " $string" : ' \(.*\)....'
H08W234

Дополнительное ведущее пространство , чтобы избежать проблем со значениями , $string которые являются фактическими exprоператорами (например, +,  /,  indexили match) или опциями (например,  --, --helpили  --version).

Скотт
источник
@ Стефан Chazelas: (1) Спасибо за напоминание мне о ловушке, которую я знал около 40 лет назад и каким-то образом удалось забыть. (2) Я всегда решал это с помощью X; например, expr "X$string" : 'X...\(.*\)'. ИМО, это легче читать и понимать. Есть ли какая-то проблема с этим, или есть какая-то причина отдать предпочтение месту? (3) Сегодня я узнал, что expr + "$string" : '...\(.*\)'теперь работает. Я не помню этого 40 лет назад; достаточно ли широко он используется, чтобы его можно было рекомендовать? (4) Вы пропустили записку об ответе Джейсонвриана и придирку к ответу Химейла.
Скотт
AFAIK, это expr +только GNU (не будет работать ни на Solaris, ни на FreeBSD AFAICS). Я использую пробел вместо x, так как менее вероятно, что некоторые exprреализации будут иметь операторы, начинающиеся с пробела, чем с, xа также потому, что менее вероятно, что элементы сортировки начинаются с пробела, чем с x. Но потом я понимаю, что это, вероятно, не лучший выбор для expr " $a" "<" " $b"сравнения строк, поскольку некоторые реализации в конечном итоге проводят численное сравнение, когда $a/ $bвыглядят как числа. Может быть expr "@@$a"...или expr "x $a"может быть безопаснее.
Стефан Шазелас
0

С:

string="H08W2345678"

Совпадение 3 или 4 символов кажется простым (для большинства оболочек):

$ printf '%s\t%s\n' "${string#???}" "${string%????}"
W2345678      H08W234

Для более старых оболочек (например, оболочки Борна) используйте:

$ string=H08W2345678

$ expr " ${string}" : " ...\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\)...." '
H08W234

Если необходимо количество символов, используйте:

$ expr " ${string}" : " .\{3\}\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\).\{4\}" '
H08W234

Конечно, эти регулярные выражения работают также с sed, awk и bash 3.0+:

$ echo "$string" | sed 's/^.\{3\}//'
W2345678

$ echo "$string" | sed 's/.\{4\}$//'
H08W234

$ echo "$string" | awk '{sub(/^.{3}/,"")}1'
W2345678

$ echo "$string" | awk '{sub(/.{4}$/,"")}1'
H08W234

$ r='^.{3}(.*)$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
W2345678

$ r='^(.*).{4}$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
H08W234
NotAnUnixNazi
источник
-1

Как «удалить» / удалить символы перед строкой?

У меня есть строка, которой я хотел бы манипулировать. Строка H08W2345678, как бы я мог манипулировать ею, чтобы вывод был просто W2345678?

echo "H08W2345678" | cut -c 4-
aexl
источник
Это отвечает только на половину вопроса.
Кусалананда
Я считаю, что ваше отрицательное мнение несправедливо. Эта половина отвечает на вопрос, который у меня возник, когда я прогуглил posix, удалив первые символы, и эта страница появилась в результатах поиска. Более того, заголовок этой страницы охватывает только ту половину вопроса. Я вернулся и внес свой вклад, когда нашел решение, которое мне понравилось - я думаю, что эта работа cutнамного элегантнее, чем все остальное на этой странице.
aexl