165

I am writing shell script for embedded Linux in a small industrial box. I have a variable containing the text pid: 1234 and I want to strip first X characters from the line, so only 1234 stays. I have more variables I need to "clean", so I need to cut away X first characters and ${string:5} doesn't work for some reason in my system.

The only thing the box seems to have is sed.

I am trying to make the following to work:

result=$(echo "$pid" | sed 's/^.\{4\}//g')

Any ideas?

jww
  • 97,681
  • 90
  • 411
  • 885
Kokesh
  • 3,165
  • 7
  • 29
  • 46
  • 10
    If `${string:5}` doesn't work then you're not using Bash or another shell that supports that syntax. What shell and version are you using? What does your shebang look like? My guess is that you're using `sh` (such as `dash`) or possibly `zsh`. – Dennis Williamson Jul 13 '12 at 12:43
  • If these pid's are always integers, then selecting the number directly with regex will be a better, simpler solutioin than trying to remove a specific number of chacters from the start. I provided an answer to this effect, but it's being downvoted, because it doesn't do specifically what you've asked for. However, what you've asked may not be the best way to solve this particular problem. – user1751825 Mar 05 '22 at 01:53

11 Answers11

229

The following should work:

var="pid: 1234"
var=${var:5}

Are you sure bash is the shell executing your script?

Even the POSIX-compliant

var=${var#?????}

would be preferable to using an external process, although this requires you to hard-code the 5 in the form of a fixed-length pattern.

chepner
  • 497,756
  • 71
  • 530
  • 681
145

Here's a concise method to cut the first X characters using cut(1). This example removes the first 4 characters by cutting a substring starting with 5th character.

echo "$pid" | cut -c 5-
al-ash
  • 197
  • 2
  • 10
Randy the Dev
  • 25,810
  • 6
  • 43
  • 54
  • 2
    Technically the OP asked for sed, but I feel like this is the best solution for "How can I strip the first X characters from string [in a terminal/bash]" When used in combination with git, it is nice: `git log --pretty=oneline | cut -c 42- | head` – marksiemers Aug 22 '18 at 00:11
  • 2
    +1 Simple and helpful solution.. When I had the URL as http:// and to cut the protocol 'http://' I have to say as 8 chars instead of 7. I don't know, but that's how it worked for me. – Santosh Kumar Arjunan Oct 15 '18 at 12:22
  • 2
    Santosh Kumar Arjunan: that's because the example "echo "$pid" | cut -c 4-" is actualy not cuting first 4 characters but extracts substring starting from 4th character. Therefore it actually cuts first 3 characters. Thus, if you want to cut 7 first characters, you want to extract everything from 8th character and thus indeed do "cut -c 8-" – al-ash Nov 28 '19 at 15:29
  • how do I do cut -c $LEN- so I can pass the amount which is in a variable? – Dean Hiller Apr 07 '20 at 20:57
  • 1
    @DeanHiller `cut -c ${LEN}-`. The curly braces are used to concatenate the string with valid variable characters, in order to distinguish what is the variable and what isn't. If you want more information on this, then look up "bash variable string concatenation" for more resources on why / how this works. – JustCarty Apr 14 '20 at 15:44
53

Use the -r option ("use extended regular expressions in the script") to sed in order to use the {n} syntax:

$ echo 'pid: 1234'| sed -r 's/^.{5}//'
1234
Mark Longair
  • 446,582
  • 72
  • 411
  • 327
24

Cut first two characters from string:

$ string="1234567890"; echo "${string:2}"
34567890
jww
  • 97,681
  • 90
  • 411
  • 885
dtp70
  • 349
  • 2
  • 4
11

pipe it through awk '{print substr($0,42)}' where 42 is one more than the number of characters to drop. For example:

$ echo abcde| awk '{print substr($0,2)}'
bcde
$
Ben
  • 9,184
  • 1
  • 43
  • 56
9

Chances are, you'll have cut as well. If so:

[me@home]$ echo "pid: 1234" | cut -d" " -f2
1234
Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
  • 1
    Trouble with `cut` is that it doesn't handle sequences of whitespace sensibly, using `tr -s ' '` to "squeeze" spaces makes it behave better. – Thor Jul 13 '12 at 13:27
  • 1
    It's not meant to be an all singing all dancing tool; it is simple and does as it says on the can and is widely available. It should work just fine for said requirements, and is certainly more robust that cropping out fixed characters from specific positions. – Shawn Chin Jul 13 '12 at 13:39
7

Well, there have been solutions here with sed, awk, cut and using bash syntax. I just want to throw in another POSIX conform variant:

$ echo "pid: 1234" | tail -c +6
1234

-c tells tail at which byte offset to start, counting from the end of the input data, yet if the the number starts with a + sign, it is from the beginning of the input data to the end.

Mecki
  • 125,244
  • 33
  • 244
  • 253
  • I really like this answer because it does *exactly* what OP asked for without using overcomplicated tools. –  Jun 14 '21 at 18:38
5

Another way, using cut instead of sed.

result=`echo $pid | cut -c 5-`
Evgeny
  • 6,533
  • 5
  • 58
  • 64
2

I found the answer in pure sed supplied by this question (admittedly, posted after this question was posted). This does exactly what you asked, solely in sed:

result=\`echo "$pid" | sed '/./ { s/pid:\ //g; }'\``

The dot in sed '/./) is whatever you want to match. Your question is exactly what I was attempting to, except in my case I wanted to match a specific line in a file and then uncomment it. In my case it was:

# Uncomment a line (edit the file in-place):
sed -i '/#\ COMMENTED_LINE_TO_MATCH/ { s/#\ //g; }' /path/to/target/file

The -i after sed is to edit the file in place (remove this switch if you want to test your matching expression prior to editing the file).

(I posted this because I wanted to do this entirely with sed as this question asked and none of the previous answered solved that problem.)

treehead
  • 264
  • 1
  • 11
0

Rather than removing n characters from the start, perhaps you could just extract the digits directly. Like so...

$ echo "pid: 1234" | grep -Po "\d+"

This may be a more robust solution, and seems more intuitive.

user1751825
  • 4,029
  • 1
  • 28
  • 58
  • I'm not sure why this is getting downvotes. The OP asked for a specific type of solution, but the solution they were asking for was not the best fit for the problem they were trying to solve. – user1751825 Mar 05 '22 at 01:44
-8

This will do the job too:

echo "$pid"|awk '{print $2}'
Arnaud F.
  • 8,252
  • 11
  • 53
  • 102
  • 35
    This question is the first hit for "skip first N characters in string". You did not answer the question. – jww Apr 22 '19 at 23:40
  • This doesn't seem to work, and if it does, can you explain how – Alexander Mills Jul 03 '19 at 03:29
  • It does work on my system. There might be an issue with your field separator, try `awk -F": " '{print $2}'`. Still, not my favourite solution. – mzuther Dec 29 '19 at 13:35
  • @jww It's a good idea sometimes to look beyond the question they're asking, to the problem they're trying to solve. This solves the OP's problem. From my experience, I've found that extracting data from strings based on character position, is rarely a robust way to solve a problem. – user1751825 Mar 05 '22 at 01:57