3

I have a bash script that swaps odd and even strings in one file, and saves it to another:

#!/bin/bash

infile="inputfile"
outfile="outputfile"

{
while read -r odd && read -r even
do
    echo "$even"
    echo "$odd"
    unset odd
done < "$infile"

# in case there are an odd number of lines in the file, print the last "odd" line read
if [[ -n $odd ]]; then
    echo "$odd"
fi
} > "$outfile"

How can I swap odd and even words in each line of the file?

Example:

Input file:

one two three four five six
apple banana cocoa dish fish nuts

Output file:

two one four three six five
banana apple dish cocoa nuts fish
1
  • 2
    edit your question to state and show your requirements if there were an odd number of words on a line. Include in your example a line with just 1 word and a line with 3 words.
    – Ed Morton
    Mar 1, 2022 at 23:13

4 Answers 4

6

Using Raku (formerly known as Perl_6)

raku -ne 'put .words.rotor(2).map(*.reverse);'  

OR

raku -ne '.words.rotor(2).map(*.reverse).put;'

OR

raku -ne '.words.rotor(2)>>.reverse.put;' 

Sample Input:

one two three four five six
apple banana cocoa dish fish nuts

Sample Output:

two one four three six five
banana apple dish cocoa nuts fish

Above are answers coded in Raku, a member of the Perl-family of programming languages. Briefly: raku is invoked at the command line using the -ne linewise non-autoprinting flag(s). When using either the -ne or -pe command line flags, each line loads into $_, a.k.a. Raku's "topic variable" ($_ is also the "topic variable" in Perl). A leading . dot is shorthand for $_. signifying that the methods that follow are to be applied to $_, the topic variable. Successive methods are chained together with the . dot operator, each transforming the input data in turn.

Going through the methods: we see the linewise input is broken on whitespace into words, then rotor-ed together into pairs of words (i.e. an argument of 2 is supplied). The name of the rotor function may be a bit obscure, but I'm guessing it is meant to signify that individual elements of a data object are cycled or rotor-ed through and grouped/clustered together. After rotor-ing, each pair is individually addressed using map, and the reverse function applied. Finally, the output in printed with put.

Note, the code above (using rotor defaults) will drop any "incomplete sets of elements" at the end. To retain "incomplete sets of elements" at the end, either change the rotor call to add a True partial parameter, or use batch which means the same thing:

raku -ne 'put .words.rotor(2, partial => True).map(*.reverse);' 

Which is the same as:

raku -ne 'put .words.rotor(2, :partial).map(*.reverse);'

Which is the same as:

raku -ne 'put .words.batch(2).map(*.reverse);'

https://raku.org

0
4

I propose this sed, suggested by @guest_7:

$ sed -e 's/\([^ ]\+\) \([^ ]\+\)/\2 \1/g' inputfile 
two one four three six five 
banana apple dish cocoa nuts fish
0
3

Usingperl it can be accomplished via clipping two leading elements from the input array of words (@F), flip them, and then append to the output array (@A)

perl -slane 'my @A;
  push @A, reverse splice @F, 0, 2
    while @F > 1;
  print @A, @F;
' -- -,=\  ./yourfile

Using the shell itself

cat yourfile |
while IFS= read -r l
do
  set -f; set -- $l
  while [ "$#" -gt 1 ]
  do
    printf '%s ' "$2" "$1"
    shift 2
  done
  echo "${1-}"
done

awk '
{
  t=$0;$0="";split(t, a)
  for (i=1; i+1 in a; i+=2) {
    $(i) = a[i+1]
    $(i+1) = a[i]
  }
  if (i in a) $(i) = a[i]
}1
' yourfile

With python, we make use of list slicing and list comprehension features:

python3 -c 'import sys
with open(sys.argv[1]) as f:
  for l in f:
    F = l.strip().split()+[""]
    print(*[f"{b} {a}" for a,b in zip(F[::2],F[1::2])])
' yourfile
2
#!/usr/bin/python
k=open('file1','r')
for line in k:
    fina_list=[]
    con=line.strip().split(' ')
    for raco in range(0,len(con),2):
        if (int(raco)%2 == 0):
            odd_cha=con[raco+1]
            even_cha=con[raco]
            con[raco]=odd_cha
            con[raco+1]=even_cha
            fina_list.append(con[raco])
            fina_list.append(con[raco+1])
    print " ".join(fina_list)

output

two one four three six five
banana apple dish cocoa nuts fish

You must log in to answer this question.

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