概要
Linuxで行う文字列処理のメモです。
Ubuntuでなるべくプリインストールされたコマンドを使っています。
行フィルター
パスワード生成
$ pwgen --symbols 12 1
Tu;qu^aey1ue
パスワードを差しさわりのない文字に置き換える
パスワードを差しさわりのない文字に置き換えるか、文字数分のダミー文字列を生成する。
$ echo "Tu;qu^aey1ue" | sed -e 's/./*/g'
************
$ python3 -c "print('*' * 12)"
************
$ ruby -e "puts('*' * 12)"
************
uuidを差しさわりのない文字に置き換える
$ uuidgen
c2663006-4033-4f6f-bd20-4044eca0ac28
$ uuidgen | tr '[0-9a-f]'
000000000-0000-0000-0000-000000000000
行単位の処理
特定のパターンに一致した行を置換する
printf "Cloudy in Tokyo.\nCloudy in Kyoto.\nCloudy in Osaka.\n" | sed -e '/Tokyo/s/Cloudy/Sunny/'
Sunny in Tokyo.
Cloudy in Kyoto.
Cloudy in Osaka.
特定のパターンに一致した行以外を置換する
printf "Cloudy in Tokyo.\nCloudy in Kyoto.\nCloudy in Osaka.\n" | sed -e '/Tokyo/!s/Cloudy/Sunny/'
Cloudy in Tokyo.
Sunny in Kyoto.
Sunny in Osaka.
特定の行を除外する
Banana と Durian を除外する。
-
入力例
Apple Banana Cherry Durian -
出力結果
Apple Cherry -
sed: 行を削除する
[Apple,Banana,Cherry,Durian] → [Apple,Cherry] のようになる$ printf "Apple\nBanana\nCherry\nDurian\n" | sed -e '/\(Banana\|Durian\)/d' Apple Cherry $ printf "Apple\nBanana\nCherry\nDurian\n" | sed -ne '/\(Banana\|Durian\)/d; p' Apple Cherry削除したリストを続けて処理できる。
$ printf "Apple\nBanana\nCherry\nDurian\n" | sed -e '/\(Banana\|Durian\)/d; s/Apple/Apple2/' Apple2 Cherry -
sed: マッチしなかった行を「表示」する ※(2025-05-27)コメントを頂いたので訂正
dの場合と異なり、表示処理された行は削除されない。
[Apple,Banana,Cherry,Durian] → [Apple,Banana,Cherry,Durian]printf "Apple\nBanana\nCherry\nDurian\n" | sed -ne '/\(Banana\|Durian\)/!p'次のコマンドにより、表示されなかった Banana の行が残っていることが分かります。
$ printf "Apple\nBanana\nCherry\nDurian\n" | sed -ne '/\(Banana\|Durian\)/!p; /Banana/p' Apple Banana Cherry例えば、ログからERROR行を表示して、INFO行を除外して
wでファイルに出力といったことができます。$ printf "INFO: aaa\nWARNING: bbb\nERROR: ccc\nINFO: ddd\n" | sed -ne '/ERROR/p; /INFO/d; w out.txt' ERROR: ccc $ cat out.txt WARNING: bbb ERROR: ccc -
Ruby
printf "Apple\nBanana\nCherry\nDurian\n" | ruby -e "STDIN.each_line(chomp: true){|v| puts v if ! ['Banana', 'Durian'].include?(v)}" -
Python
printf "Apple\nBanana\nCherry\nDurian\n" | python3 -c "import sys; [print(line) for line in list(filter(lambda x: x not in ['Banana', 'Durian'], [line.rstrip('\n') for line in sys.stdin.readlines()]))]"
テキストで行をまたがる処理
行末に空白文字があるファイルを探す
-
行末に空白文字があるファイルを探す
grep -nr '[[:blank:]]$' --include='*.rs' .find . -type f -name '*.rs' -exec egrep -l " +$" {} \;
テキストの先頭に行を追加する
-
catを使う
-は標準入力から読み取ります。そのあと、ファイルから読み取ります。#!/bin/bash TMP_FILE=$(mktemp $0-XXX.txt) && { cat > $TMP_FILE <<EOF Cherry Durian EOF printf "Apple\nBanana\n" | cat - $TMP_FILE rm -f $TMP_FILE } -
sedを使う
#!/bin/bash TMP_FILE=$(mktemp $0-XXX.txt) && { cat > $TMP_FILE <<EOF Cherry Durian EOF sed -e '1s/^/Apple\nBanana\n/' $TMP_FILE rm -f $TMP_FILE }
マッチした次の行を置換する
パターンの後に {} でブロックをかける。ブロックの中で n が次の行を示す。
-
コード例
printf "remote:\n - id: primary\nkey:\n - id: foo\nacl:\n - id: update_acl\n" | sed -e '/^key:/{n; s/id: .*/id: UUUUUU/}' -
入力例
remote: - id: primary key: - id: foo acl: - id: update_acl -
出力例
remote: - id: primary key: - id: UUUUUU acl: - id: update_acl
テーブル処理
指定の列を取り出す
4列目を取り出す例。
小数点を含む計算、データを振り分けて集計する、など複雑化してきたら、ほかの言語での実装を検討しましょう。
どの環境でも使用できるメリットを考えれば Python が第一候補で、数値計算にも対応しやすいのは利点。
メソッドチェーンでわりと直観かつ簡潔に記述したいなら Ruby でもよい。
-
入力
$ ps PID TTY TIME CMD 79597 pts/10 00:00:00 bash 89456 pts/10 00:00:00 ps -
Bash配列
入力データが単純なスペース区切りの場合は、Bash配列のほうが楽(awkの知識を不要とできる)になる場合がある。ps | while read LINE; do a=($LINE) echo "${a[3]}" done -
GAWK
取り出した列そのものが出力結果だったり、区切り文字の指定が必要な場合は GAWK が便利。ps | awk '{print $4}'