単語による変数の内容の反転


13

だから変数を持っているなら

VAR='10 20 30 40 50 60 70 80 90 100'

エコーします

echo "$VAR"
10 20 30 40 50 60 70 80 90 100

ただし、スクリプトをさらに下に移動すると、この変数の順序が逆になり、次のように表示されます。

echo "$VAR" | <code to reverse it>
100 90 80 70 60 50 40 30 20 10

revを使用してみましたが、文字通りすべてが逆転したため、

echo "$VAR" | rev
001 09 08 07 06 05 04 03 02 01

2
この類似の質問への回答には、いくつかの有用な提案があります。IPアドレスを逆読みする方法は?(ピリオドの代わりにスペース区切り文字を調整する必要があります)
steeldriver

回答:


21

GNUシステムでは、catの逆はtacです。

$ tac -s" " <<< "$VAR "            # Please note the added final space.
100 90 80 70 60 50 40 30 20 10

乾杯!それはトリックをしました。私はまだ学ぶべきことがたくさんあります
アリステアハーディ

@JhonKugelmanエコーがない場合、出力には次のような改行が追加されます。 echo $'100 \n90 80 70 60 50 40 30 20 10'
sorontar

現在のtac -s" " <<< "$VAR "バージョンでは、先頭の空白行が挿入され、末尾のスペースが追加され、末尾の改行文字が省略されます(あたかもprintf '\n%s ' "$reversed_VAR"予想される代わりにprintf '%s\n' "$reversed_VAR"
ステファンChazelas

@don_crissti元の答え:echo $(tac -s" " <<< $VAR)末尾のスペースはありません。$(…) IFSに後続の改行とスペースがある場合、後続の改行とスペースが削除される。私の解決策はすぐに修正されます、ありがとう。
-sorontar

6

短いリストと変数の場合、シェル自体が最速のソリューションです。

var="10 20 30 40 50 60 70 80 90 100"
set -- $var; unset a 
for ((i=$#;i>0;i--)); do
    printf '%s%s' "${a:+ }" "${!i}"
    a=1
done
echo

出力:

100 90 80 70 60 50 40 30 20 10 

注:での分割操作は、set -- $varここで使用されている正確な文字列に対して安全ですが、文字列にワイルドカード文字(*?または[])が含まれる場合はそうではありません。避けることができますset -f必要に応じて、分割前ます。同じ注記は、以下のソリューションにも適用されます(注記がある場合を除く)。

または、逆のリストを使用して他の変数を設定する場合:

var="10 20 30 40 50 60 70 80 90 100"
set -- $var
for i; do out="$i${out:+ }$out"; done
echo "$out"

または、定位置パラメーターのみを使用します。

var="10 20 30 40 50 60 70 80 90 100"
set -- $var
a=''
for    i
do     set -- "$i${a:+ $@}"
       a=1
done
echo "$1"

または、1つの変数のみを使用します(変数自体の場合もあります)。
注:このソリューションは、グロビングやIFSの影響を受けません。

var="10 20 30 40 50 60 70 80 90 100"

a=" $var"
while [[ $a ]]; do
    printf '<%s>' "${a##* }"
    var="${a% *}"
done

2

awk 救助へ

$ var='10 20 30 40 50 60 70 80 90 100'

$ echo "$var" | awk '{for(i=NF; i>0; i--) printf i==1 ? $i"\n" : $i" "}'
100 90 80 70 60 50 40 30 20 10


perl、礼儀IPアドレスを逆読みする方法は?@steeldriverで共有

$ echo "$var" | perl -lane '$,=" "; print reverse @F'
100 90 80 70 60 50 40 30 20 10


または、bash文字列を配列に変換することにより、それ自体で

$ arr=($var)    
$ for ((i=${#arr[@]}-1; i>=0; i--)); do printf "${arr[i]} "; done; echo
100 90 80 70 60 50 40 30 20 10 

2

配列などのbash機能を使用して、完全にインプロセスで実行できます。

#!/bin/bash
VAR="10 20 30 40 50 60 70 80 90 100"
a=($VAR); rev_a=()
for ((i=${#a[@]}-1;i>=0;i--)); do rev_a+=( ${a[$i]} ); done; 
RVAR=${rev_a[*]}; 

これは、$ VARがそれほど大きくないという条件で、最速の方法です。


ただし、値にワイルドカード文字(などVAR='+ * ?')が含まれる変数には適用されません。set -o noglobまたはset -fを使用して修正します。より一般的には$IFS、split + glob演算子を使用する場合、グロビングの値と状態を考慮することをお勧めします。ありません、それはにその演算子を使用するためにはほとんど意味がrev_a+=( ${a[$i]} )rev_a+=( "${a[$i]}" )より多くの理にかなって。
ステファンシャゼル16年


1

ここでPythonの魔法を少し使用してください:

bash-4.3$ VAR='10 20 30 40 50 60 70 80 90 100'
bash-4.3$ python -c 'import sys;print " ".join(sys.argv[1].split()[::-1])'  "$VAR" 
100 90 80 70 60 50 40 30 20 10

これが機能する方法は非常に簡単です。

  • "$VAR"2番目のコマンドラインsys.argv[1]パラメーターと呼びます(-cオプションのある最初のパラメーターは常に-cそれだけです- それ自体。"$VAR"変数自体が個々の単語に分割されるのを防ぐために符で囲むことに注意してください(これはPythonではなくシェルによって行われます)
  • 次に使用します .split()、メソッドして、文字列のリストに分割します
  • [::-1] 一部はただ 拡張スライス構文です 、リストの逆を取得するための
  • 最後に、すべてを1つの文字列に結合して" ".join()出力します

しかし、Pythonの大ファンではない人は、AWK基本的に同じことを行うことができます:分割し、配列を逆に印刷します。

 echo "$VAR" | awk '{split($0,a);x=length(a);while(x>-1){printf "%s ",a[x];x--};print ""}'
100 90 80 70 60 50 40 30 20 10 

1
またはややクリーンpython3 -c 'import sys;print(*reversed(sys.argv[1:]))' $VAR
iruvar

@iruvar、ないクリーナーを確認することなしに、シェルの分割+グロブ演算子を呼び出します、$IFS適切な文字が含まれているとグロブ一部を無効にすることなく。
ステファンシャゼル16年

@StéphaneChazelas、本当です-Python部分はまだきれいです(私見)。したがって、"$VAR"利回りに戻るpython3 -c 'import sys;print(*reversed(sys.argv[1].split()))' "$VAR"
-iruvar

1

zsh

print -r -- ${(Oa)=VAR}

$=VARで分割$VAR$IFSます。(Oa)結果のリストを逆配列順に並べます。print -r --(のようにksh)、echo -E -zsh特定の)と同じは信頼できるバージョンですecho:引数をそのままスペースで区切って出力し、改行で終了します。

$IFS(スペース、タブ、改行、nulをデフォルトで含む)ではなくスペースのみで分割する場合は、にスペースを割り当てるか、次の$IFSような明示的な分割を使用します。

print -r -- ${(Oas: :)VAR}

逆の数値順に並べ替えるには:

$ VAR='50 10 20 90 100 30 60 40 70 80'
$ print -r -- ${(nOn)=VAR}
100 90 80 70 60 50 40 30 20 10

POSIXly(だからも動作しますbash):

シェル組み込み(printf一部のシェルを除く)メカニズムのみ(値が短い変数の場合):

unset -v IFS # restore IFS to its default value of spc, tab, nl
set -o noglob # disable glob
set -- $VAR # use the split+glob operator to assign the words to $1, $2...

reversed_VAR= sep=
for i do
  reversed_VAR=$i$sep$reversed_VAR
  sep=' '
done
printf '%s\n' "$reversed_VAR"

awk(特にと、大規模な変数のためのより良いbash)が、引数の大きさの限度まで(または単一の引数の):

 awk '
   BEGIN {
     n = split(ARGV[1], a);
     while (n) {printf "%s", sep a[n--]; sep = " "}
     print ""
   }' "$VAR"

0

エレガントなPOSIXソフトウェアツールワンライナー:

echo `echo $VAR | tr ' ' '\n' | sort -nr`
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.