9
2492  some string continues here

I would like to convert this to

2492

in Bash. How would I go about that?

This feels close, but is not working:

var="2492  some string continues here  "
echo ${var%[[:space:]]*}
2
  • Will there never be leading whitespace?
    – Alexander
    Apr 13, 2018 at 8:27
  • If you are asking how to do it in bash you should probably not be using bash to do it. Use Perl or something.
    – Ben
    Apr 13, 2018 at 9:34

6 Answers 6

15

Because there are multiple spaces you want to use

${var%%[[:space:]]*}
# ...^^

to remove the longest trailing substring that starts with a space

With just a single % you're removing the shortest sequence of a space followed by zero or more characters, which is just the last space in the string.

$ echo ">$var<"; echo ">${var%[[:space:]]*}<"; echo ">${var%%[[:space:]]*}<"
>2492  some string continues here  <
>2492  some string continues here <
>2492<

If you're just looking for the first word, you can do this:

read -r word rest_of_string <<<"$var"
echo "I have: $word"

That will take care of leading whitespace, assuming you have not altered the IFS variable.

5
  • How about if there is a leading space in the string? ` 2492 some string continues here` Apr 12, 2018 at 20:56
  • That will remove all the characters. Apr 12, 2018 at 21:05
  • [:space:] character class includes space, tab, CR, NL, etc. So it's a catch-all for any whitespace. Apr 12, 2018 at 22:36
  • 1
    a=($var); echo "${a[0]}" also works for accessing the first word in the case of leading whitespace. Apr 12, 2018 at 22:52
  • You expose the value to filename expansion as well as word splitting unless you do set -f first Apr 12, 2018 at 22:58
4

There is the simple solution of using %% (${var%% *})instead of % (${var% *}). That will remove everything (*) after an initial space.

$ var='2492  some string continues here'
$ echo "${var%% *}"
2492

But that will fail if the string in var has any leading spaces. It is possible to remove the leading spaces with:

$ var=$' \t 2492  some string continues here  '
$ var="${var#"${var%%[![:space:]]*}"}"
$ echo "$var"
2492  some string continues here  
$ echo "${var%%[[:space:]]*}"
2492

That works even if the white-spaces are spaces tabs NL or CR.


Regex

Maybe a more robust solution is to use a regex:

$ var=$' \t 2492  some string continues here  '
$ regex='^[[:space:]]*([^[:space:]]+)'
$ [[ $var =~ $regex ]] && var=${BASH_REMATCH[1]}
$ echo "$var"
2492
1
  • 1
    I think that's the first time I've seen anyone refer to regular expressions as "more robust" ;-)
    – Kusalananda
    Apr 13, 2018 at 7:06
2

You can also use the simple tool cut, who cuts strings based on a delimiter :

echo "$mystring" | cut -d' ' -f 1 

Where :

  • -d' ' sets the delimiter to a space
  • -f 1 gives the first field (based on the delimiter)
1
  • I like this one. No regular expressions, no programming languages.
    – gronostaj
    Apr 13, 2018 at 15:07
1

You can use native shell string manipulation:

TEST="test  1234 foo"
SPLIT_VAR=${TEST/ */ }

It will replace the first pattern matching " *" (one space then anything) and replace it with " " (one space). So you keep the first word and the first space.

You can see http://www.tldp.org/LDP/abs/html/string-manipulation.html for more usage of string manipulation.

And as a side note, it's also works less evolved shell (tested on busybox's ash implementation).

0

To use only bash and builtin commands, you could use Internal Field Seperator(IFS) and arrays

set -f                # To prevent filename globbing when creating the array, as pointed out by Kusalananda in the comments
array=(2492 some string continues here)
set +f                # enable it again
IFS=" "
echo "${array[0]}"
unset IFS
9
  • Try that with a string that starts with e.g. *.
    – Kusalananda
    Apr 13, 2018 at 7:17
  • @Kusalananda tried it with array=(*2492* *some * *string continues* here)- still works Apr 13, 2018 at 7:21
  • Now add a file in the current directory that contains 2492 in its name, for example myfile-2492.txt, and run again.
    – Kusalananda
    Apr 13, 2018 at 7:23
  • 1
    @Kusalananda oh wow, why does this happen ? Apr 13, 2018 at 7:31
  • 1
    @Kusalananda, I guess I'll have to start with set -f and end with set +f ? Apr 13, 2018 at 7:37
0

If you don't mind an external call, use awk or sed:

$ string="first second third fourth"
$ echo "${string}" | awk '{print $1}' # will work even with tabs
first
$ echo "${string}" | sed -e "s/ .*$//" # will fail on leading whitespace
first
2

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .