17

I have the following input:

Value1|Value2|Value3|Value4@@ Value5|Value6|Value7|Value8@@ Value9|etc...

In my bash script I would like to replace the @@ with a newline. I have tried various things with sed but I'm not having any luck:

line=$(echo ${x} | sed -e $'s/@@ /\\\n/g')

Ultimately I need to parse this whole input into rows and values. Maybe I am going about it wrong. I was planning to replace the @@ with newlines and then loop through the input with setting IFS='|' to split up the values. If there is a better way please tell me, I am still a beginner with shell scripting.

2
  • 1
    a gnu sed of recentish version should work with ...|sed 's/@@ /\n/g'.. . Good luck.
    – shellter
    Commented May 7, 2014 at 15:40
  • 1
    awk with RS="@@ " and FS="|" Commented May 7, 2014 at 16:10

7 Answers 7

14

Using pure BASH string manipulation:

eol=$'\n'
line="${line//@@ /$eol}"

echo "$line"
Value1|Value2|Value3|Value4
Value5|Value6|Value7|Value8
Value9|etc...

Or else do it in single step:

line="${line//@@ /$'\n'}"
5
  • Sadly this did not work...it did not replace the "@@ " at all line="${x//@@ /$eol}" Commented May 7, 2014 at 15:42
  • @odinsride: Make sure you use BASH. See with working demo: ideone.com/ePzOxq
    – anubhava
    Commented May 7, 2014 at 15:52
  • 1
    Variation that doesn't require the separate eol definition is to replace $eol with a literal newline (as in, hit Enter, and the final }" appears at the beginning of the next line). Not as clear, but useful for code golf. The " around it are mandatory though, even if nothing else in the string would require them (since the newlines will get turned back into spaces in most [all?] contexts if it's not quoted). Commented Mar 10, 2023 at 16:39
  • 1
    Another way to avoid defining eol would be to move $'...' into the curly brackets: line="${line//@@ /$'\n'}". It works in my terminal, eg: echo "${PATH//:/$'\n'}" prints all dirs from my PATH line by line.
    – saulius2
    Commented Apr 20, 2023 at 17:51
  • 1
    Yes @saulius2 that should work for sure
    – anubhava
    Commented Apr 20, 2023 at 17:55
12

This will work

sed 's/@@ /\n/g' filename

replaces @@ with new line

3
  • @rpax thanks for editing forgot to format my answer
    – prudviraj
    Commented Jun 26, 2014 at 12:26
  • You are welcome. Anyway, this is a good answer. I like it. +1
    – rpax
    Commented Jun 26, 2014 at 12:28
  • You don't have to escape the first @, and this is missing a space after @@. Commented Sep 25, 2018 at 18:37
8

I recommend using the tr function

echo "$line" | tr '@@' '\n'

For example:

[itzhaki@local ~]$ X="Value1|Value2|Value3|Value4@@ Value5|Value6|Value7|Value8@@"
[itzhaki@local ~]$ X=`echo "$X" | tr '@@' '\n'`
[itzhaki@local ~]$ echo "$X"
Value1|Value2|Value3|Value4

 Value5|Value6|Value7|Value8
6
  • This did not work in my script, it still has the '@@ ' in the output: echo $x | tr '@@ ' '\n' >> $OUTPUT Commented May 7, 2014 at 15:47
  • I know for a fact it works. I'm using "tr" all the time. Make sure you're using BASH and not SH, and that you're looking at the right output. Here, run this: pastebin.com/gxvKUwS9
    – itzhaki
    Commented May 7, 2014 at 16:01
  • 4
    As far as I know, tr works on individual characters, not strings. As in, tr 'Ab' 'aB' turns Abracadabra into aBracadaBra. Commented May 7, 2014 at 16:29
  • 2
    You just need to "squeeze": tr -s '@' '\n' Commented Jun 26, 2014 at 13:20
  • 2
    The question asks to replace @@ plus a blank, though. tr can't do that. Commented Sep 25, 2018 at 18:38
4

Finally got it working with:

sed 's/@@ /'\\\n'/g'

Adding the single quotes around \\n seemed to help for whatever reason

4

If you don't mind to use perl:

echo $line | perl -pe 's/@@/\n/g'
Value1|Value2|Value3|Value4
 Value5|Value6|Value7|Value8
 Value9|etc
1

How about:

for line in `echo $longline | sed 's/@@/\n/g'` ; do
    $operation1 $line
    $operation2 $line
    ...
    $operationN $line
    for field in `echo $each | sed 's/|/\n/g'` ; do
        $operationF1 $field
        $operationF2 $field
        ...
        $operationFN $field
    done
done
1
  • Edited answer to make solution compatible with performing operations on both rows and fields in those rows. Commented May 7, 2014 at 16:10
0

This wraps up using perl to do it, and gives some simple help.

$ echo "hi\nthere"
hi
there

$ echo "hi\nthere" | replace_string.sh e
hi
th
re

$ echo "hi\nthere" | replace_string.sh hi


there

$ echo "hi\nthere" | replace_string.sh hi bye
bye
there

$ echo "hi\nthere" | replace_string.sh e super all
hi
thsuperrsuper

replace_string.sh

#!/bin/bash

ME=$(basename $0)
function show_help()
{
  IT=$(cat <<EOF

  replaces a string with a new line, or any other string, 
  first occurrence by default, globally if "all" passed in

  usage: $ME SEARCH_FOR {REPLACE_WITH} {ALL}

  e.g. 

  $ME :       -> replaces first instance of ":" with a new line
  $ME : b     -> replaces first instance of ":" with "b"
  $ME a b all -> replaces ALL instances of "a" with "b"
  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$1" ]
then
  show_help
fi

STRING="$1"
TIMES=${3:-""}
WITH=${2:-"\n"}

if [ "$TIMES" == "all" ]
then
  TIMES="g"
else
  TIMES=""
fi

perl -pe "s/$STRING/$WITH/$TIMES"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.