Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 如何反转shell字符串中的单词列表?_Linux_Shell_Awk_Sed_Ash - Fatal编程技术网

Linux 如何反转shell字符串中的单词列表?

Linux 如何反转shell字符串中的单词列表?,linux,shell,awk,sed,ash,Linux,Shell,Awk,Sed,Ash,我有一个字符串中的单词列表: str="SaaaaE SeeeeE SbbbbE SffffE SccccE" 我想把它倒过来,以便 "SccccE SffffE SbbbbE SeeeeE SaaaaE" 如何使用ash实现这一点?是的,您可以尝试这些命令 对于字符串 echo "aaaa eeee bbbb ffff cccc"|tr ' ' '\n'|tac|tr '\n' ' ' echo $str|tr ' ' '\n'|tac|tr '\n' ' ' 对于变量 echo "a

我有一个字符串中的单词列表:

str="SaaaaE SeeeeE SbbbbE SffffE SccccE"
我想把它倒过来,以便

"SccccE SffffE SbbbbE SeeeeE SaaaaE"

如何使用ash实现这一点?

是的,您可以尝试这些命令

对于字符串

echo "aaaa eeee bbbb ffff cccc"|tr ' ' '\n'|tac|tr '\n' ' '
echo $str|tr ' ' '\n'|tac|tr '\n' ' '
对于变量

echo "aaaa eeee bbbb ffff cccc"|tr ' ' '\n'|tac|tr '\n' ' '
echo $str|tr ' ' '\n'|tac|tr '\n' ' '
您可以使用awk:

echo "aaaa eeee bbbb ffff cccc" | awk '{for(i=NF;i>0;--i)printf "%s%s",$i,(i>1?OFS:ORS)}'
在字段中向后循环,打印每个字段
OFS
是输出字段分隔符(默认为空格),
ORS
是输出记录分隔符(换行符)


我假设您不希望每个单词中的字母顺序颠倒。

您可以使用
awk
,如下所示:

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

这里有一个
awk
使用
do
,而
(在Stackoverflow中使用不多)
无需额外变量
i

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


****反转字符串的程序***


进入这里:我爱我的印度

你已经进入:我爱我的印度


字符串的反面:India My love I

如果使用Haskell是可以接受的,那么有一个很好的工具叫做hawk(Haskell awk),它可以很容易地做到这一点。首先,您需要安装它:

$ cabal install haskell-awk
然后:


您需要在<代码>路径<代码> <代码> >鹰> <代码> > < /p> < p>如果您需要纯外壳,没有外部工具,请考虑:

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

reverse_word_order "$str"
否则,
tac
可以立即帮助您:

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

tac-s'sed分组:

str="SaaaaE SeeeeE SbbbbE SffffE SccccE"

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

另一个纯bash解决方案:

str='test a is this'; res=""; prev=""
while [ "$prev" != "$str" ]; do res="$res${str##* } "; prev="$str"; str="${str% *}"; done

这适用于
sh
(我没有
ash
,因此无法验证):

像这样使用它:

$ reversed=$(reverse foo bar baz)
$ echo $reversed
baz bar foo
这里有一些替代方案。首先,对于
,不使用C样式的

reverse() {
    while [ ${#*} -gt 0 ]
    do
      echo ${*: -1}
      set -- "${@:1:$(($#-1))}"
    done
}
下一个(来自)在替换不起作用的情况下起作用(例如,在Android上)


我试图找到一个在Android脚本中工作的解决方案,
sh
不喜欢C风格的
或复杂的替换操作。我以最后一个示例结束,因为它两者都不使用。

如果要从文件中读取输入(如此处所述:), 我创建了以下bash脚本,它可以在不改变文件行顺序的情况下反向打印每行的单词(例如,在阅读单词RTL而不是LTR(中文)时,我需要这样做):

#/bin/bash
fileName=“$1”
outputFile=“ReversedFile.npp”
echo>${outputFile}
lineCount=`cat$fileName | wc-l`
对于((lineNum=1;${lineNum}>wordFile.txt
完成
如果[-e wordFile.txt];则
thisLine=“”
wordCount=`cat wordFile.txt | wc-l`
for((wordNum=${wordCount};${wordNum}>=1;wordNum--))
做
wordOfLine=“`cat wordFile.txt | head-${wordNum}| tail-1`”
echo“${wordCount}的${wordNum}是${wordOfLine}”
thisLine+=“${wordOfLine}”
完成
回声“输出”
回显“${thisLine}”
回显“${thisLine}”>${outputFile}
rm-f wordFile.txt
fi
完成
回声
echo“文件${outputFile}中的输出”

笔记:
1) 确保输入文件为UNIX EOL格式,否则每行的最后一个字都可能被截断
2) 为了简单起见,可能省略了一些错误检查

BASH 这是我使用的函数(未在ash中测试)

正如0andriy所暗示的,我们可以这样做,(或者如果您的平台有
tac
,但没有
tr
):

rwo(){echo“$*”| tac-s“;}#dash兼容

rwo(){tac-s”“这是对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
它做了一些假设,例如没有前导空格或尾随空格,所有的单词都被一个空格隔开。带前导空格或尾随空格的行保持不变,没有被一个空格隔开的行保留多余的空格,这可能不是我们想要的

脚本应该与任何符合POSIX的sed和基本正则表达式(BRE)一起使用

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

对于主要替换,但如果您首先使用sed解决此问题,可读性可能不是首要问题。

使用
do…的awk解决方案,而
在输入字符串为空时抛出错误,而一些使用
for
循环的awk解决方案在输入字符串为空时将打印一个空行。这比以前的awk解决方案略短,不存在POSIX中行为未定义的问题,
--NF
,并且在输入为空字符串时不会抛出错误或打印空行:

$echo“aaaa eeee bbbb ffff cccc”| awk'{i=NF;而(i)printf“%s”,$i(i-->1?FS:RS)}
cccc ffff bbbb eeee aaaa

tac在我的ashok中不受支持抱歉,我在bash中运行了此命令,但我保留此命令以供将来的读者帮助。稍微短一点的
awk'{do printf“%s”(NF>1?of s:ORS),$NF;while(--NF)}“
@Jidder,谢谢。如果使用
FS:RS
而不是
OFS:ORS
--NF
的效果是每个POSIX都有未定义的行为,因此在不同的awk版本中,这种行为会有所不同。awk答案更具指导性和实用性。禁止使用shell读取行。更不用说提示了用户。这不是命令行的内容。rwo(){for((i=${};i>0;i--){echo${!i};};};}tr的无用用法?
tac-s”“…
reverse() {
    if [ "$#" -gt 0 ]; then
        local arg=$1
        shift
        reverse "$@"
        printf '%s\n' "$arg"
    fi
}
#!/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}"
#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
rwo(){ echo "$*"|tr ' ' '\n'|tac|tr '\n' ' ';}
rwo(){ echo "$*"|tac -s " ";} #dash compatible 
rwo(){ tac -s " "<<<"$@";} #bashism
#!/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
s/\n(\S+) (.*) (\S+)\n/\3 \n\2\n \1/