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


187

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

#! /bin/sh 

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

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

回答:


115

POSIXシェルでは、構文${t:-2}は何か異なることを意味します-if が設定されてnull以外の値に展開され、それ以外のt場合tはvalueに展開されます2。パラメーターの展開によって1文字をトリムするには、おそらく必要な構文は${t%?}

in ksh93bashor zsh${t:(-2)}または${t: -2}(スペースに注意)部分文字列の展開として有効ですが、末尾から2文字目の位置から始まる部分文字列を返す(つまり、最初の文字iを削除するため)文字列ijk)。

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


4
「%」の背後にある魔法とは何かを説明したいですか??
-afraisse

8
@afraisse ${parameter%word}は、最短のサフィックスパターンマッチングを削除しますword-のパラメーター拡張セクションを参照してくださいman bash
steeldriver

3
これは、Bash 4.1.2でうまく機能します。CentOS/ RHEL 6.xを使用
ジョーイT

185

bash4.2以上、あなたが行うことができます。

${var::-1}

例:

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

古いものbashbash 3.2.5OS Xなど)の場合は、コロンの前後にスペースを入れてください:

${var: : -1}

13
これはbashバージョン4.2-alpha以降で機能しますが、アクセスできるバージョンが以前のものよりも悪いです。:-/
hjk

2
@iamaziz:bashの変更ログから、の負の長さ${var:offset:lenght}はのみに追加されましたbash 4.2。たぶん、OSXは独自のパッチを追加しbashます。
クオングルム

1
@cuonglmも動作しません:/
iamaziz

1
Macでは機能しません。
-shinzou

1
MACstersは、ラスの答えを見下ろす
PのI

67

ORをn使用しない行から最後の文字を削除する場合:sedawk

> 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

62

sedを使用すると、

sed 's/.$//'

その場合、単一のエコーecho ljk | sed 's/.$//'です。
これを使用すると、1行の文字列は任意のサイズになります。


10
一般的な場合には、それがないことに注意してください、文字列の最後の文字を削除、しかし最後の文字列のすべての行のを
ステファンシャゼル16

44

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

  • 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いくつかの実装で)。また、文字列に無効な文字が含まれている場合、予期しない結果が生じる可能性があります。


素敵で徹底!しかし...これらのシェルはすべてPOSIXをサポートしているので、誰でもそのシェルを使用して最も移植性の高いものにする必要があります。最小の文字数も!
ラス

@Russ t=${t%?}はBourne ではありませんが、最近ではBourneシェルに出くわすことはないでしょう。${t%?}しかし、他のすべてで機能します。
ステファンシャゼラス

フィッシュシェルオプションはありません!最近はksh93よりもおそらく人気があります
...-rien333

@ rien333。インターフェースが少し安定するのを待ちます。fish進行中の作業です。string組み込みを導入した2.3.0 は、Q&Aの時点ではリリースされていません。私がテストしているバージョンでは、あなたは必要ですstring replace -r '(?s).\z' '' -- $t(そして、彼らはそれを変更したいと思うでしょう、彼らはPCREに渡すフラグを変更するべきです)またはより複雑なもの。また、改行文字の処理が不十分であり、改行文字の変更も計画していることを知っています。
ステファンシャゼル

POSIXの回答に賛成です。Bash 3.2.57(1)の作業を確認
Avindra Goolcharan

26

最もポータブルで最短の答えは、ほぼ確実です。

${t%?}

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

これは、旧式のシェルパラメータ拡張を使用して機能します。具体的には、globパターンに一致する%パラメーターの最小一致サフィックス(つまり、任意の文字)を削除するように指定します。t?

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


サイドノートとして、代わりに最初の文字を削除する場合は、を使用します${t#?}。これ#は、後ろ(サフィックス)ではなく、文字列(プレフィックス)の前から一致するためです。

また、注目に値するの両方のことである%#有する%%##一致するバージョン、その最長の代わりに最短の所定のパターンのバージョン。ただし、この場合、両方の${t%%?}and ${t##?}は単一の演算子と同じように動作します(したがって、無駄な余分な文字を追加しないでください)。これは、指定された?パターンが単一の文字にのみ一致するためです。*いくつかの非ワイルドカードとa を混ぜると、andで物事がより面白く%%なり##ます。

パラメータ展開を理解すること、または少なくともその存在とその検索方法を知ることは、多くの種類のシェルスクリプトを記述および解読するのに非常に役立ちます。多くの人にとって、パラメーター展開はしばしば難解なシェルのブードゥーのように見えます。それ ...よく...それら不可解なシェルのブードゥーだからです(ただし、「パラメーターの展開」を探すことを知っていれば、かなりよく文書化されています)。ただし、シェルで立ち往生しているときは、ツールベルトに入れておくと間違いありません。


短くて甘く、MacOSとLinuxの両方で動作します!
dbernard

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

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

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

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

たとえば、Ubuntuの上で、/bin/shありますdash


15

またhead、最後の文字以外のすべてを印刷するために使用できます。

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

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


5

正規表現を使用して行うのは簡単です:

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

5

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

SRC_IP_MSG=${SRC_IP_MSG%??}

4

純粋な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/%\ /}'"

最初の構文は文字列から部分文字列を取ります。構文は 次のとおりです。2番目の構文では、符号に注意してください。
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}

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

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

ここで再び%記号に注目してください。これは、 'Remove(つまり、' 'で置換)最短一致パターン(ここではPARAMETERの末尾のエスケープされたスペース' \ 'で表されます -ここではSTRという名前)


1

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

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

配管あり:

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

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