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/