web-dev-qa-db-fra.com

Comment inverser une liste de mots dans une chaîne de shell?

J'ai une liste de mots dans une chaîne:

str="SaaaaE SeeeeE SbbbbE SffffE SccccE"

Je veux inverser pour obtenir

"SccccE SffffE SbbbbE SeeeeE SaaaaE"

Comment puis-je faire cela avec ash?

12
MOHAMED

Vous pouvez utiliser awk comme suit:

echo "$str" | awk '{ for (i=NF; i>1; i--) printf("%s ",$i); print $1; }'
16
Feten besbes

Oui, vous pouvez essayer ces commandes, 

Pour string,

echo "aaaa eeee bbbb ffff cccc"|tr ' ' '\n'|tac|tr '\n' ' '

Pour la variable,

echo $str|tr ' ' '\n'|tac|tr '\n' ' '
9
Skynet

Vous pouvez utiliser awk:

echo "aaaa eeee bbbb ffff cccc" | awk '{for(i=NF;i>0;--i)printf "%s%s",$i,(i>1?OFS:ORS)}'

Parcourez les champs en arrière et imprimez-les. OFS est le séparateur de champ de sortie (un espace par défaut) et ORS est le séparateur d'enregistrement de sortie (nouvelle ligne).

Je suppose que vous ne voulez pas que l'ordre des lettres dans chaque mot soit inversé.

6
Tom Fenech

Voici une awk utilisant dowhile (peu utilisée ici à Stackoverflow)
Aucune variable supplémentaire nécessaire i

echo "aaaa eeee bbbb ffff cccc"|awk '{do printf "%s"(NF>1?FS:RS),$NF;while(--NF)}'
cccc ffff bbbb eeee aaaa
4
Jotne

si vous avez besoin de pur Shell, sans outils externes, prenez en compte ceci:

reverse_Word_order() {
    local result=
    for Word in $@; do
        result="$Word $result"
    done
    echo "$result" 
}

reverse_Word_order "$str"

Sinon tac peut vous aider tout de suite:

echo -n "$str" | tac -s' '

ou

tac -s' ' <<<"$str" | xargs 
2
anandi

groupement sed:

str="SaaaaE SeeeeE SbbbbE SffffE SccccE"

echo $str | sed 's/\(.* \)\(.* \)\(.* \)\(.* \)\(.*\)/\5 \4\3\2\1/g'
1
Aguevara

Si utiliser Haskell est acceptable, il existe un outil de Nice appelé hawk (haskell-awk) qui peut le faire très facilement. Vous devez d'abord l'installer:

$ cabal install haskell-awk

Ensuite:

$ echo $str | hawk -m reverse

Vous avez besoin de ~/.cabal/bin dans votre PATH pour trouver hawk.

1
Jens Petersen

Cela fonctionne dans sh (je n'ai pas ash alors je ne peux pas le vérifier):

reverse() {
    for (( i = ${#*}; i > 0; i-- ))
    {
        echo ${!i}
    }
}

utilisez-le comme ceci:

$ reversed=$(reverse foo bar baz)
$ echo $reversed
baz bar foo

Voici quelques alternatives. Tout d'abord, celui qui n'utilise pas le style C for:

reverse() {
    while [ ${#*} -gt 0 ]
    do
      echo ${*: -1}
      set -- "${@:1:$(($#-1))}"
    done
}

Le prochain (de ici ) fonctionne là où les substitutions ne fonctionnent pas (par exemple sur Android)

reverse() {
    if [ "$#" -gt 0 ]; then
        local arg=$1
        shift
        reverse "$@"
        printf '%s\n' "$arg"
    fi
}

J'essayais de trouver une solution qui fonctionnait dans un script Android, dans laquelle sh n'aimait pas les opérations de substitution de type C for ou complexes. J'ai fini avec le dernier exemple car il n'utilise ni l'un ni l'autre.

1
starfry

BASH

C’est la fonction que j’utilise, (non testée en cendre)

#reverse_Word_order
function rwo(){ tr ' ' '\n'<<<"$@"|tac|tr '\n' ' ';}
echo $(rwo 'Hello There I am You')
#based on https://stackoverflow.com/a/27703859/1153645

TIRET

(fonctionne également en bash, mais certaines personnes semblent avoir une aversion pour l'écho)

rwo(){ echo "$*"|tr ' ' '\n'|tac|tr '\n' ' ';}
0
Alexx Roche

Une autre solution pure bash:

str='test a is this'; res=""; prev=""
while [ "$prev" != "$str" ]; do res="$res${str##* } "; prev="$str"; str="${str% *}"; done
0
Fabien Bouleau
/* Shell script to reverse the Input String */    
echo " **** Program to Reverse a String **** "
read -p " Enter Here : " text

echo "You have entered : " $text

echo -n "Reverse of String : "

arr=($text)

arrlength=${#arr[@]}

arrlength=`expr $arrlength - 1`

while [ $arrlength -ge 0 ]
do

echo -n ${arr[arrlength]}
echo -n " "
 arrlength=`expr $arrlength - 1`
done

echo

SORTIE


**** Programme pour inverser une chaîne ***


Entrez ici: j'aime mon Inde

Vous avez entré: J'aime mon Inde

Reverse of String: India Mon amour, je

0
Bhupender Singh

Ceci est une légère adaptation du Caractères inversés des lignes script dans le manuel GNU sed:

#!/usr/bin/sed -f

# Skip lines without blanks
/[[:blank:]]/! b

# Embed line between newlines
s/^.*$/\
&\
/

# Reset the t flag
tx

# Label to jump to
:x

# Swap first and last Word between newlines for three or more words
s/\n\([^[:blank:]][^[:blank:]]*\) \(.*\) \([^[:blank:]][^[:blank:]]*\)\n/\3 \
\2\
 \1/

# Jump to label if there was a change on the line
tx

# Swap first and last Word between newlines for exactly two words
s/\n\([^[:blank:]][^[:blank:]]*\) \([^[:blank:]][^[:blank:]]*\)\n/\2\
 \
\1/

# Remove the newline markers
s/\n//g

Il fait quelques hypothèses telles que l’absence de blancs en début et en fin de texte et que tous les mots sont séparés par un seul espace. Les lignes avec des espaces en début ou en fin de ligne restent inchangées et les lignes où les mots ne sont pas séparés par un seul espace laissent les espaces supplémentaires où ils se trouvent, ce qui pourrait ne pas correspondre à ce que vous souhaitez.

Le script doit fonctionner avec toutes les expressions rationnelles BRE (BRE). L'utilisation de GNU expressions régulières sed et étendues (ERE) permettrait une meilleure lisibilité, telle que

s/\n(\S+) (.*) (\S+)\n/\3 \n\2\n \1/

pour la substitution principale, mais si vous utilisez sed pour résoudre ce problème en premier lieu, la lisibilité n'est probablement pas la principale préoccupation.

0
Benjamin W.

Si l'entrée doit être lue à partir d'un fichier (comme demandé ici: lire ligne inversée à partir d'un fichier ), le fichier (j'en avais besoin par exemple lors de la lecture de mots RTL au lieu de LTR en chinois, etc.):

#!/bin/bash

fileName="$1"
outputFile="ReversedFile.npp"

echo > ${outputFile}
lineCount=`cat $fileName | wc -l`
for ((lineNum=1; ${lineNum} <= ${lineCount}; lineNum++))
do
    echo
    echo "Processing Line ${lineNum} of ${lineCount} ..."

    lineOfFile="`cat $fileName | head -${lineNum} | tail -1`"
    echo "${lineOfFile}"

    rm -f wordFile.txt
    for eachWord in `echo "${lineOfFile}"`
    do
        echo "${eachWord}" >> wordFile.txt
    done

    if [ -e wordFile.txt ]; then
        thisLine=""
        wordCount=`cat wordFile.txt| wc -l`
        for ((wordNum=${wordCount}; ${wordNum}>=1; wordNum--))
        do
            wordOfLine="`cat wordFile.txt | head -${wordNum} | tail -1`"
            echo "${wordNum} of ${wordCount} is ${wordOfLine}"
            thisLine+="${wordOfLine} "
        done
        echo "output"
        echo "${thisLine}"
        echo "${thisLine}" >> ${outputFile}
        rm -f wordFile.txt
    fi
done

echo
echo "Output in File ${outputFile}"


Remarques:
1) Assurez-vous que le fichier d'entrée est au format UNIX EOL, sinon le dernier mot pourrait être tronqué à partir de chaque ligne
2) Certaines vérifications d'erreur ont peut-être été omises pour des raisons de simplicité

0
harshvchawla