3

What shell script should I use in Linux to replace a group with n lines of text with a single line?

I have a file like :

a
b
c
*
d
e
f
*
g
h
i
*

and I want to get a file as:

abc
def
ghi
famedoro
  • 1,223
  • 2
  • 17
  • 41
  • Something like 'i=0; while read line; do test $((++i))', but I haven't found any solution – famedoro Jan 10 '14 at 09:08
  • I just saw your answer http://stackoverflow.com/a/21042715/1983854 . Why don't you give proper input? All the approaches were based on your input which is very far from the one you are using in your answer. – fedorqui Jan 10 '14 at 11:17
  • 1
    @fedorqui and besides, his/her answer is the longest and least understandable of all :) – holgac Jan 10 '14 at 11:44

8 Answers8

2

can use awk

awk '{if ($0=="*"){print s;s=""}else{s=s$0}}' file

an bash way to this is

while read x
do
   [ "$x" == "*" ] && echo  || echo -n $x
done < file
ray
  • 4,109
  • 1
  • 17
  • 12
2

sed way:

sed ':a;N;$!ba;s/\n//g' < t | sed 's:*:\n:g'

t is the file you want to change.

references: How can I replace a newline (\n) using sed? Why does sed not replace all occurrences?

The first command replaces \n with nothing. the second replaces * with \n.

sed is a very powerful stream editor tool by the way, knowing it can help you in more ways than you can imagine.

Community
  • 1
  • 1
holgac
  • 1,509
  • 1
  • 13
  • 25
1

Other than awk solution :

tr '\n' ' ' < Input.txt |sed 's/ //g' | tr '*' '\n'
Debaditya
  • 2,419
  • 1
  • 27
  • 46
0

One awk way:

$ awk '/\*/ {printf "\n"; next} {printf $1}' file
abc
def
ghi
  • In case of *, print a new line. Otherwise, print the character. Using printf, so that new line is not added unless specified.

With xargs:

$ xargs -n4 < file | cut -d' ' -f1-3
a b c
d e f
g h i
  • xargs -n4 < file prints the file in blocks of 4 columns. cut -d' ' -f1-3 prints from 1st to 3rd column.
fedorqui
  • 275,237
  • 103
  • 548
  • 598
0

If you treat * as the line token, try remove '\n' and replace STAR.

cat <youfile> | tr -d '\n' | tr '*' '\n'
Mohammad AbuShady
  • 40,884
  • 11
  • 78
  • 89
NTj
  • 385
  • 2
  • 10
  • 1
    instead of using 2 pipes, you could have said `tr -d '\n' < file | tr '*' '\n'` – ray Jan 10 '14 at 09:21
0

You can do it in the shell without awk, or tr, or anything external too:

#!/bin/bash
while read x
do
   if [ "$x" == "*" ]; then
      echo $line
      line=""
   else
      line="$line$x"
   fi
done

Save as "go", then do:

chmod +x go
./go <inputfile
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
0

I believe tr could be considered the correct tool to replace single characters.

tr -d '\n' < file | tr '*' '\n'

Correct in this context would mean most lightweight, least clumsy, least bug-prone, and least cognitively demanding for the purpose. The other solutions work, but tr has the least hidden costs. When you use a lot of small tools as you do in unix, these small advantages really add up over time.

cmc
  • 4,294
  • 2
  • 35
  • 34
0

Thanks to everybody, I've found this solution which works in case the file is like

field1     2008
field2     703
field3     qeew
field4     80
field5     52
field6     749.11

field1     2009
field2     532
field3     wecwer
field4     82
field5     44
field6     649.97

...

#!/bin/bash

if [ "$1" = "" ]
then
   echo "missing file name"
   exit 1
fi

N=7
i=0
FULL_ROW=""
SAVEIFS=$IFS
if [ -f $1 -a -r $1 ]; then
    LAST_DATA_SCAD=""
    while IFS=$(echo -en "|\n\b") read -ra ROW_RECORD; do

    if [[ "$FULL_ROW" == "" ]]
       then
        FULL_ROW=${ROW_RECORD:11}
       else
        FULL_ROW=$FULL_ROW"|"${ROW_RECORD:11}
    fi
    i=$((i+1))
    if [ $((10#$i)) == $N ]
    then
      echo $FULL_ROW
      FULL_ROW=""
      i=0
    fi
    done < "$1"
   else
     echo "file not found"
   fi
   IFS=$SAVEIFS
famedoro
  • 1,223
  • 2
  • 17
  • 41