How can I obtain below output? I want the first field as it is and a single character after space.

echo "Hello world"

If it also has a 3rd field than the beginning character of the 3rd field should be in the output.

echo "hello world unix"

Using awk to output the first whitespace-delimited word concatenated with the first character of the last whitespace-delimited word:

awk '{ print $1 substr($NF, 1, 1) }'

The substr() function returns a number of characters from a given position of a string, and $1 and $NF is the first and last whitespace-delimited word on the current line, respectively.


$ echo 'hello world' | awk '{ print $1 substr($NF, 1, 1) }'
$ echo 'apple beet carrot' | awk '{ print $1 substr($NF, 1, 1) }'
  • Will not this duplicated the first letter of a word for a line with that single word only? – αғsнιη Apr 14 at 6:41
  • @αғsнιη Yes it would. The question does not specify what should happen in the case when there is only a single word. – Kusalananda Apr 14 at 6:43

With sed:

Edit: improved by glenn jackmann, thanks!

$ echo "Hello world" | sed -E 's/(\S+).*\s(\S).*$/\1\2/'
$ echo "hello world unix" | sed -E 's/(\S+).*\s(\S).*$/\1\2/'

Description with "hello world unix" as example:

  • s/ substitute the following pattern
  • (\S+) 1st group, one or more non-space characters: "hello"
  • .* the middle part, any characters: " world"
  • \s space character: " "
  • (\S) 2nd group, non-space character: "u"
  • .*$ any characters up to the end: "nix"
  • /\1\2/ replace with 1st and 2nd group: "hellou"

With bash:

$ var="Hello world"
$ var_end=${var##* };echo ${var%% *}${var_end:0:1}

$ var="hello world unix"
$ var_end=${var##* };echo ${var%% *}${var_end:0:1}

Description with "hello world unix" as example:

  • var_end=${var##* } remove matching prefix pattern, longest match,
    "hello world ", result: "unix"
  • ${var%% *} remove matching suffix pattern, longest match,
    " world unix", result: "hello"
  • ${var_end:0:1} get the first character: "u"
  • Your regex can be a bit simpler: you don't need to capture the 2nd group, and it can contain any characters: ^(\S+).*\s(\S) will do. Also, I believe the perl-like regex means you must use GNU sed. – glenn jackman Apr 14 at 12:03

Using bash:

text="hello world unix"
if [[ $text =~ ^([^[:space:]]+).*[[:space:]]([^[:space:]]) ]]; then
    declare -p BASH_REMATCH
    echo "${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
declare -ar BASH_REMATCH='([0]="hello world u" [1]="hello" [2]="u")'
  • just curious to understand to know, why is declare -p needed here? The array is already populated right? – Inian Apr 15 at 5:05
  • It's not needed at all. Merely to show the contents of the array, to see the results of the regex match with capturing parentheses. – glenn jackman Apr 15 at 10:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.