4

How do I print the remainder of a string (not just the columns without the delimiter) after the nth delimiter?

I have a text file with a bunch of registry keys, similar to:

hku\test\user\software\microsoft\windows\currentversion\runonce\delete cached update binary

I'm wanting to print everything after the 3rd \ character. So I am looking for the output to be

software\microsoft\windows\currentversion\runonce\delete cached update binary

I know how to print out specific columns with awk, but is there any simple way using bash to specify a delimiter to split the string at, instead of using the delimiter to print columns?

AdminBee
  • 22,803
john doe
  • 836

6 Answers6

12

Pipe through cut -d \\ -f 4-.

echo 'hku\test\user\software\microsoft\windows\currentversion\runonce\delete cached update binary' | cut -d \\ -f 4-

Yields:

software\microsoft\windows\currentversion\runonce\delete cached update binary

Note the double \\, since a single \ is an escape character.

user33593
  • 306
  • 2
  • 3
6

With sed:

sed -E 's/^([^\]*[\]){3}//' infile

or the same in awk:

awk '{ sub(/([^\\]*[\\]){3}/, "") }1' infile

Match repeated of (regex) 3times; [^\]*[\] matches on zero-or-more of any-characters but not a back-slash (plus not a newline exceptionally) followed by a back-slash character.


And the shell (POSIX sh/bash/Korn/zsh) solution:

$ str='hku\test\user\software\microsoft\windows\currentversion\runonce\delete cached update binary'
$ for i in $(seq 3); do str="${str#*\\}"; done
$ printf '%s\n' "$str"

The ${parameter#word} syntax is the Parameter Expansion, that strips the shortest prefix from its parameter.

αғsнιη
  • 41,407
3

Using awk:

awk 'BEGIN{FS=OFS="\\"; }{for(i=4;i<NF;i++) printf "%s", $i OFS; print $NF }' input

Because we want to print everything after the 3rd \ character, Field separaror FS and output field separator OFS are set to \. FS="\\" because single \ is escape character. Because \ is now filed separator we use a for loop to print from filed number 4 to last field of record.

Or like this:

awk 'BEGIN{FS=OFS="\\"; }{for(i=4;i<=NF;i++) printf "%s", $i (i==NF?ORS:OFS) }' input

Here everything is same but ternary operator is used. Here for loop will print OFS after $i for all but last field. After last field this will print ORS i.e. a newline.

Another method:

awk 'BEGIN{OFS="\\"} { n=split($0,arr,OFS); $0=""; for (i=4; i<=n; ++i) $(i-3)=arr[i]; print }' input

Here split() built-in function splits $0 by OFS and creates an array arr. Then for loop changes every field of record by $(i-3)=arr[i]. For example for first element of for loop, $1 will be arr[4]. Why $1 because $(4-3) is $1. When loop is completed awk has a new $0 that starts from fourth field of old record ($0). Then print command prints new $0.

αғsнιη
  • 41,407
2
## input variables
n=3
s='hku\test\user\software\microsoft\windows\currentversion\runonce\delete cached update binary'

sed Change the n-th backslash to a newline, a character known to not be present, we then strip away everything till the newline.

printf '%s\n' "$s" |
sed -e '
  s/\\/\n/'"$n"'
  s/.*\n//
' -
software\microsoft\windows\currentversion\runonce\delete cached update binary

linux command line Convert to one-field per line, chop off the first n fields, and then join them back.

printf '%s\n' "$s" | tr '\\' '\n' | tail -n+"$((n+1))" | paste -sd '\\' -

bash builtins

set -f;IFS=\\;
declare -a a=( $s )
printf '%s\n' "${a[*]:$n}"

awk

printf '%s\n' "$s" |
awk -F '\' -v n="$n" '
NF>n {
  for (i=p=1; i<=n; i++) 
    p += 1+length($i)
  $0 = substr($0,p)
}1' -

printf '%s\n' "$s" |
perl -pals -F'/\\/,$_,$n+1' -e '
  $_=$F[-1];
' -- -n="$n"  -

python3 -c 'import sys
p,(s,n) = -1,sys.argv[1:]
for i in range(1+int(n)):
  p = 1+s.find("\\",p)
print(s[p:])
' "$s" "$n"
αғsнιη
  • 41,407
guest_7
  • 5,728
  • 1
  • 7
  • 13
1

Just to not miss perl:

perl -e '@a=split /\\/, $ARGV[0]; print(join("\\", splice @a, 3), "\n")' $str

Where str is the path.

Or without the endings new line :

perl -e '@a=split /\\/, $ARGV[0]; print join "\\", splice @a, 3' $str
0
awk -F"\\" '{ OFS="\\"; $1=$2=$3=""; sub(/\\*/,""); print }' filename

output

software\microsoft\windows\currentversion\runonce\delete cached update binary
αғsнιη
  • 41,407