web-dev-qa-db-ja.com

シェルスクリプトで文字列操作を使用して文字列の最後の文字を削除する

文字列の最後の文字を削除したいので、次の小さなスクリプトを試しました。

#! /bin/sh 

t="lkj"
t=${t:-2}
echo $t

しかし、それは「lkj」を出力します、私は間違っていますか?

207
user3581976

POSIXシェルでは、構文${t:-2}は別の意味を持ちます。tが設定されていてnull以外の場合はtの値に展開され、それ以外の場合は値2に展開されます。パラメータ展開によって単一の文字をトリミングするには、おそらく必要な構文は${t%?}です。

ksh93bashまたはzsh${t:(-2)}または${t: -2}(スペースに注意)は部分文字列として有効であることに注意してください。展開されますが、最後から2文字後の位置にある部分文字列を返すため(つまり、first文字i文字列ijk)。

詳細については、Bashリファレンスマニュアルのシェルパラメータ拡張セクションをご覧ください。

122
steeldriver

bash 4.2以降では、次のことができます。

${var::-1}

例:

$ a=123
$ echo "${a::-1}"
12

古いbash(たとえば、bash 3.2.5(OS Xの場合)、コロンの間とコロンの後にスペースを入れてください:

${var: : -1}
211
cuonglm

Sedを使用すると、

sed 's/.$//'

あなたのシングルechoecho ljk | sed 's/.$//'
これを使用すると、1行の文字列は任意のサイズにすることができます。

70

n OR sedを使用しない行から最後のawk文字を削除するため:

> echo lkj | rev | cut -c (n+1)- | rev

たとえば、最後の文字one characterを次のように削除できます。

> echo lkj | rev | cut -c 2- | rev

> lk

revマンページから:

説明
revユーティリティは、指定されたファイルを標準出力にコピーし、各行の文字の順序を逆にします。ファイルが指定されていない場合は、標準入力が読み取られます。

更新:

文字列の長さがわからない場合は、次のことを試してください。

$ x="lkj"
$ echo "${x%?}"
lk
70
Nidal

シェルに応じたいくつかのオプション:

  • POSIX:_t=${t%?}_
  • ボーン:t=`expr " $t" : ' \(.*\).'`
  • zsh/yash:_t=${t[1,-2]}_
  • bash/zsh:_t=${t:0:-1}_
  • ksh93/bash/zsh/mksh:_t=${t:0:${#t}-1}_
  • ksh93/bash/zsh/mksh:_t=${t/%?}_
  • ksh93:t=${t/~(E).$/}
  • es:_@ {t=$1} ~~ $t *?_

すべてが最後の文字を取り除くことになっていますが、一部の実装(マルチバイト文字をサポートしないもの)が最後のバイトを取り除くことに気付くでしょう(マルチバイトの場合、最後の文字が破損する可能性があります)。

exprバリアントは、_$t_が複数の改行文字で終了しないことを前提としています。結果の文字列が最終的に_0_(または一部の実装では_000_または_-0_)になった場合も、ゼロ以外の終了ステータスを返します。文字列に無効な文字が含まれている場合も、予期しない結果が生じる可能性があります。

50

最も移植性があり、最も短い答えはほぼ確実です。

${t%?}

これは、bash、sh、ash、dash、busybox/ash、zsh、kshなどで機能します。

古い学校のシェルパラメーター展開を使用して動作します。具体的には、%は、グロブパターン?(つまり、任意の文字)に一致するパラメーターtの最小一致サフィックスを削除することを指定します。

詳細な説明と背景については、「最小のサフィックスパターンの削除」 ここ を参照してください。また、「パラメータ展開」のシェルのドキュメント(例:man bash)も参照してください。


補足として、代わりにfirst文字を削除したい場合は、${t#?}を使用します。これは、#が文字列の先頭から一致するためです(接頭辞)の代わりに(接尾辞)。

また、%#の両方に%%##のバージョンがあり、これらはバージョンの最長バージョン最短の代わりに与えられたパターン。ただし、${t%%?}${t##?}はどちらも、この場合の単一の演算子と同じように機能します(不要な文字を追加しないでください)。これは、指定された?パターンが単一の文字にのみ一致するためです。 *といくつかの非ワイルドカードを組み合わせて、%%##を使用すると、物事がより面白くなります。

パラメータ展開を理解すること、または少なくともそれらの存在を理解し、それらを調べる方法を知ることは、多くのフレーバーのシェルスクリプトを記述および解読するのに非常に役立ちます。多くの人にとって、パラメータ展開は多くの場合、難解なシェルブードゥー教のように見えます...ええと...それら難解なシェルブードゥー教(ただし、「パラメーター展開")。ただし、シェルで立ち往生している場合は、ツールベルトに入れておくことをお勧めします。

36
Russ
t=lkj
echo ${t:0:${#t}-1}

0から文字列長-1までの部分文字列を取得します。ただし、この減算はbash固有であり、他のシェルでは機能しないことに注意してください。

たとえば、dashは解析することさえできません

echo ${t:0:$(expr ${#t} - 1)}

たとえば、Ubuntuでは/bin/shdashです

18
Ángel

headを使用して、最後の文字を除くすべてを出力することもできます。

$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin

ただし、残念ながら、headの一部のバージョンには、先頭の-オプションが含まれていません。これは、OS Xに付属するheadの場合です。

15
greenbeansugar

正規表現を使用するのは簡単です。

n=2
echo "lkj" | sed "s/\(.*\).\{$n\}/\1/"
6
unxnut

SteelDriverとNetworkerに感謝します!

文字列の長さがわからない場合は、次のことを試してください。

$ x="lkj"
$ echo "${x%?}"
lk
6
drill

いくつかの改良。複数の文字を削除するには、複数の疑問符を追加できます。たとえば、変数から最後の2文字を削除するには:$SRC_IP_MSG、次のものを使用できます。

SRC_IP_MSG=${SRC_IP_MSG%??}
6
yuliskov

純粋なbashのいくつかの可能な使用法を完了するために:

#!/bin/bash

# Testing substring removal
STR="Exemple string with trailing whitespace "
echo "'$STR'"
echo "Removed trailing whitespace: '${STR:0:${#STR}-1}'"
echo "Removed trailing whitespace: '${STR/%\ /}'"

最初の構文は文字列から部分文字列を取り、構文は
${STRING:OFFSET:LENGTH}
2番目のものについては、%記号。これは「行末から」を意味し、構文は
${STRING/PATTERN/SUBSTITUTION}

そして、ここに上記の2つの短い形式があります

echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"

ここで再び%記号、つまり「削除(つまり ''で置換)を意味しますshortest一致パターン(ここではエスケープスペースで表されます'\'[〜#〜]パラメータの最後から[〜#〜]-ここでは[〜#〜] str [〜#〜]

4
CermakM

コマンドラインまたはシェルスクリプトでphpを使用することもできます。時々、外科的解析に役立ちます。

php -r "echo substr('Hello', 0, -1);" 
// Output hell

配管あり:

echo "hello" | php -r "echo substr(trim(fgets(STDIN)), 0, -1);"
// Output hell
1
NVRM