概要
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: 行を削除する
$ printf "Apple\nBanana\nCherry\nDurian\n" | sed -e '/\(Banana\|Durian\)/d' Apple Cherry
削除したリストを続けて処理できる。
$ printf "Apple\nBanana\nCherry\nDurian\n" | sed -e '/\(Banana\|Durian\)/d; s/Apple/Apple2/' Apple2 Cherry
-
sed: マッチしなかった行を「表示」する
printf "Apple\nBanana\nCherry\nDurian\n" | sed -ne '/\(Banana\|Durian\)/!p'
「表示」したデータは捨てられるので、続けて置換をしても効果はない。
$ printf "Apple\nBanana\nCherry\nDurian\n" | sed -ne '/\(Banana\|Durian\)/!p; s/Apple/Apple2/' Apple Cherry
-
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}'