Linux/Bash 文字列の後ろから削除する完全ガイド!末尾処理のすべての方法

Linux

「ファイル名から拡張子を削除したい」 「パスの最後のスラッシュを取りたい」 「末尾の改行や空白を削除したい」

Linuxでは文字列の後ろから文字を削除する方法が 10種類以上もあるんです!

bashのパラメータ展開、sed、awk、cut… それぞれ得意な処理が違います

この記事を読めば、 あらゆる末尾削除処理を 最適な方法で実装できるようになります!


スポンサーリンク

Bashパラメータ展開(最速・最も簡単)

後ろから指定文字数を削除

# 基本構文:${変数:0:-削除文字数}

# 後ろから3文字削除
text="hello.txt"
echo ${text:0:-3}  # hello.

# 後ろから4文字削除
filename="document.pdf"
echo ${filename:0:-4}  # document

# 変数で文字数を指定
string="abcdefghij"
n=3
echo ${string:0:-$n}  # abcdefg

# 実践例:タイムスタンプ削除
file="backup_20240115.tar.gz"
echo ${file:0:-17}  # backup

パターンマッチで末尾削除

# %パターン:最短マッチを削除
# %%パターン:最長マッチを削除

# 拡張子を削除(最短マッチ)
file="archive.tar.gz"
echo ${file%.*}   # archive.tar(.gzだけ削除)
echo ${file%%.*}  # archive(.tar.gzすべて削除)

# 末尾のスラッシュを削除
path="/home/user/documents/"
echo ${path%/}    # /home/user/documents

# 特定の文字列を削除
text="hello_world_2024"
echo ${text%_*}   # hello_world(最短)
echo ${text%%_*}  # hello(最長)

# 数字を削除
string="file123"
echo ${string%[0-9]}    # file12(1文字)
echo ${string%%[0-9]*}  # file(すべての数字)

実践的な使用例

#!/bin/bash

# 拡張子を変更する関数
change_extension() {
    local file=$1
    local new_ext=$2
    echo "${file%.*}.${new_ext}"
}

# 使用例
change_extension "document.txt" "pdf"  # document.pdf

# バッチ処理で拡張子削除
for file in *.jpg; do
    name=${file%.jpg}
    echo "処理中: $name"
    # 何か処理
done

# パスからファイル名だけ取得
fullpath="/var/log/system.log"
filename=${fullpath##*/}  # system.log
dirname=${fullpath%/*}    # /var/log

sedコマンドで末尾削除

基本的な末尾削除

# 末尾のn文字を削除
echo "hello world" | sed 's/.\{3\}$//'  # hello wo

# 末尾の1文字を削除
echo "test123" | sed 's/.$//'  # test12

# 末尾の5文字を削除
echo "filename.txt" | sed 's/.\{4\}$//'  # filename

# 複数行に対して処理
cat file.txt | sed 's/.\{2\}$//'  # 各行の末尾2文字削除

# ファイルを直接編集
sed -i 's/.\{3\}$//' file.txt

パターンで末尾削除

# 末尾の数字を削除
echo "file123" | sed 's/[0-9]*$//'  # file

# 末尾の空白を削除
echo "hello   " | sed 's/[[:space:]]*$//'  # hello

# 末尾の特定文字列を削除
echo "test.backup" | sed 's/\.backup$//'  # test

# 拡張子を削除
echo "document.pdf" | sed 's/\.[^.]*$//'  # document

# 末尾の改行を削除
echo -e "line1\n\n" | sed ':a;/^\n*$/{$d;N;ba}'

高度なsed処理

# 末尾の括弧内を削除
echo "function(param1, param2)" | sed 's/([^)]*)$//'  # function

# URLのクエリパラメータを削除
echo "https://example.com/page?id=123" | sed 's/\?.*$//'

# 末尾のバージョン番号を削除
echo "app-v1.2.3" | sed 's/-v[0-9.]*$//'  # app

# 条件付き削除(特定の行のみ)
sed '/^#/s/.\{2\}$//' file.txt  # コメント行のみ末尾2文字削除

awkコマンドで末尾処理

substr関数で削除

# 後ろからn文字削除
echo "hello world" | awk '{print substr($0, 1, length($0)-3)}'  # hello wo

# 変数を使った削除
echo "test12345" | awk -v n=3 '{print substr($0, 1, length($0)-n)}'

# フィールド単位で処理
echo "one two three" | awk '{$NF=substr($NF,1,length($NF)-2); print}'

# CSVの特定カラムの末尾処理
echo "a,b,c123" | awk -F, '{$3=substr($3,1,length($3)-3); print}' OFS=,

正規表現での削除

# gsubで末尾パターン削除
echo "file.txt" | awk '{gsub(/\.[^.]*$/, ""); print}'  # file

# 末尾の数字削除
echo "test123" | awk '{gsub(/[0-9]+$/, ""); print}'  # test

# 複数パターンの削除
echo "data_2024_backup" | awk '{
    gsub(/_backup$/, "")
    gsub(/_[0-9]{4}$/, "")
    print
}'

cutコマンド(シンプルだが制限あり)

revと組み合わせて末尾削除

# 後ろから3文字削除(revで反転)
echo "hello world" | rev | cut -c4- | rev  # hello wo

# 関数化
remove_last_n() {
    echo "$1" | rev | cut -c$(($2+1))- | rev
}

remove_last_n "test12345" 3  # test12

# パイプラインで処理
cat file.txt | while read line; do
    echo "$line" | rev | cut -c3- | rev
done

その他のコマンド

headコマンド

# バイト単位で削除(GNU head)
echo "hello world" | head -c -3  # hello wo

# 改行も考慮
echo -n "test123" | head -c -2  # test1

perlワンライナー

# 後ろから3文字削除
echo "hello world" | perl -pe 's/.{3}$//'

# 拡張子削除
echo "file.txt" | perl -pe 's/\.[^.]*$//'

# 末尾の空白削除
echo "text   " | perl -pe 's/\s+$//'

pythonワンライナー

# 後ろから3文字削除
echo "hello world" | python3 -c "import sys; print(sys.stdin.read()[:-3])"

# より柔軟な処理
echo "test123" | python3 -c "
import sys
text = sys.stdin.read().strip()
print(text[:-3] if len(text) > 3 else '')
"

ファイル名の一括処理

拡張子の一括削除

#!/bin/bash

# 方法1:forループ
for file in *.txt; do
    newname="${file%.txt}"
    mv "$file" "$newname"
done

# 方法2:findとexec
find . -name "*.bak" -exec sh -c '
    for file; do
        mv "$file" "${file%.bak}"
    done
' sh {} +

# 方法3:renameコマンド(perl版)
rename 's/\.txt$//' *.txt

# 方法4:mmv(要インストール)
mmv "*.txt" "#1"

安全なリネーム関数

#!/bin/bash

safe_trim_rename() {
    local pattern="$1"
    local trim_chars="$2"
    
    for file in $pattern; do
        [ ! -f "$file" ] && continue
        
        # 末尾から指定文字数削除
        newname="${file:0:-$trim_chars}"
        
        # ファイルが既に存在する場合の処理
        if [ -f "$newname" ]; then
            echo "警告: $newname は既に存在します"
            continue
        fi
        
        echo "リネーム: $file → $newname"
        mv "$file" "$newname"
    done
}

# 使用例
safe_trim_rename "*.backup" 7

特殊なケース

改行・空白の削除

# 末尾の改行を削除
text=$(echo -e "hello\n\n")
echo -n "$text" | sed 's/\n*$//'

# 末尾の空白と改行を削除
echo "  text  " | sed 's/[[:space:]]*$//'

# tr コマンドで改行削除
echo -e "line1\nline2\n" | tr -d '\n'

# 末尾の空白行を削除
sed -i '/^[[:space:]]*$/d' file.txt

特定の区切り文字まで削除

# 最後のスラッシュ以降を削除
path="/home/user/documents/file.txt"
echo ${path%/*}  # /home/user/documents

# 最後のドット以降を削除(拡張子)
file="archive.tar.gz"
echo ${file%.*}  # archive.tar

# 最後のアンダースコア以降を削除
name="project_v1_final"
echo ${name%_*}  # project_v1

パフォーマンス比較

#!/bin/bash

# テストデータ
string="This is a test string with some text"
iterations=10000

# Bashパラメータ展開(最速)
time for i in $(seq 1 $iterations); do
    result=${string:0:-5}
done

# sed(遅い)
time for i in $(seq 1 $iterations); do
    result=$(echo "$string" | sed 's/.....$//')
done

# awk(中間)
time for i in $(seq 1 $iterations); do
    result=$(echo "$string" | awk '{print substr($0,1,length($0)-5)}')
done

よくあるエラーと対処法

エラー1:空文字列での処理

# ❌ エラーになる可能性
text=""
echo ${text:0:-3}  # エラー

# ✅ 安全な処理
text=""
if [ -n "$text" ] && [ ${#text} -gt 3 ]; then
    echo ${text:0:-3}
else
    echo "$text"
fi

エラー2:文字数が足りない

# ❌ 問題のあるコード
text="ab"
echo ${text:0:-5}  # エラーまたは予期しない結果

# ✅ 長さチェック付き
trim_end() {
    local string="$1"
    local n="$2"
    
    if [ ${#string} -gt $n ]; then
        echo "${string:0:-$n}"
    else
        echo ""
    fi
}

trim_end "ab" 5  # 空文字列を返す

まとめ:用途別ベストプラクティス

単純な文字数削除:

${variable:0:-n}  # Bashパラメータ展開が最速

パターンマッチ削除:

${variable%pattern}  # 拡張子削除など

複数行処理:

sed 's/.{n}$//' file.txt  # ファイル全体を処理

複雑な条件:

awk '{条件処理}' file  # 柔軟な処理が可能

大量ファイルの処理:

find + xargs または parallel  # 並列処理で高速化

文字列の末尾削除をマスターすれば、 シェルスクリプトが格段に便利になります!

用途に応じて最適な方法を選んで、 効率的な文字列処理を実現しましょう。


コメント

タイトルとURLをコピーしました