Awk 如何翻转字符串的最后一个字符

Awk 如何翻转字符串的最后一个字符,awk,Awk,我试图在1和2之间翻转字符串的最后一个字符。我需要理解为什么system2能够转换为system1,而system1不能转换为system2 还有,有没有更聪明的方法来做这个翻转呢?这是因为你把$NF改成了2,这使得第二个条件变为真,它又变回了1。你需要另一个 我可以在sed中想出一个更简单的解决方案: sed 's/1$/2/;t;s/2$/1/' 它使用t命令,如果未指定标签,则在上一次替换成功的情况下转到脚本末尾 另一种可能的解决方案使用Perl: perl -pe 's/([12])$

我试图在1和2之间翻转字符串的最后一个字符。我需要理解为什么system2能够转换为system1,而system1不能转换为system2


还有,有没有更聪明的方法来做这个翻转呢?

这是因为你把$NF改成了2,这使得第二个条件变为真,它又变回了1。你需要另一个

我可以在sed中想出一个更简单的解决方案:

sed 's/1$/2/;t;s/2$/1/'
它使用t命令,如果未指定标签,则在上一次替换成功的情况下转到脚本末尾

另一种可能的解决方案使用Perl:

perl -pe 's/([12])$/ $1 =~ tr=12=21=r /e'
匹配最后的1或2,并在其上运行音译。您可以对shell中的tr使用类似的技巧:

printf '%s' ${string:0:-1}
printf '%s\n' ${string: -1} | tr 12 21
在不进行剥离的情况下,您可以使用例如参数扩展和算术:

if [[ $string = *[12] ]] ; then
   echo ${string%[12]}$((3-${string: -1}))
else
    echo $string
fi

你可以试着纠正一下奥普的错误

echo system1|awk -vFS="" '{if($NF==1){gsub($NF,2);print;next};if($NF==2)gsub($NF,1)}1'
OP的尝试不起作用的原因:

由于第一个条件为真,$NF为1,它将其更改为2,现在第二个条件为真,2再次替换为1,因此它给出相同的输出

我解决这个问题的尝试是:由于OP的尝试代码非常特定于GNUAWK,所以我们可以尝试以下哪种更通用的解决方案

echo system1 | 
awk '
{
   val=substr($0,length($0))
   printf("%s%s\n",substr($0,1,length($0)-1),val==1+0?2:(val==2?1:val))
   val=""
}'
这类似于oguzismail的方法

仅当最后一个字符为1或2时更改。 1%2+1=2,2%2+1=1。
要使任何awk简洁、坚固且便于携带,应:

$ echo system2| awk '!sub(/1$/,2){sub(/2$/,1)}1'
system1
$ echo system1| awk '!sub(/1$/,2){sub(/2$/,1)}1'
system2

第一种解决方案不适用于两种输入,它有相同的问题,但适用于另一种输入。@choroba,谢谢您的告知,现在更改了它。您为什么需要awk来完成此操作?shell内置程序可以很好地用于此目的。您有很多awk答案都依赖于将FS设置为null,将输入拆分为字符。这是每个POSIX未定义的行为,因此在某些awk中它会这样做,而在其他awk中它会将输入作为一行保留在1个字段中,而在其他awk中它仍然可以执行任何其他操作,并且仍然符合POSIX。该awk脚本是一个糟糕的脚本。首先,它依赖于将FS设置为null,将字符串拆分为字符,但根据POSIX,这是未定义的bahavior,因此它实际上会在不同的AWK中执行不同的操作。然后,如果它将输入拆分为字符,它将用1或2替换整行中出现的最后一个字符。
echo system1 | 
awk '
{
   val=substr($0,length($0))
   printf("%s%s\n",substr($0,1,length($0)-1),val==1+0?2:(val==2?1:val))
   val=""
}'
awk 'BEGIN{FS=OFS=""}($NF==1||$NF==2){$NF=$NF%2+1}1'
$ echo system2| awk '!sub(/1$/,2){sub(/2$/,1)}1'
system1
$ echo system1| awk '!sub(/1$/,2){sub(/2$/,1)}1'
system2