それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

gitbookのビルドだけをgulpでフォルダ監視して自動実行したい

gitbook-cli でサーバーがいちいち上がるのがめんどくさい。

gitbook を使い込む気は、あまりないのだけど、マークダウンを記述して、gitbook serve で 変換が必要

gulp で監視してしまいたい。

HTMLに変換するだけなら、べつにserve は要らないし、そこまでリアルタイムな編集も要らないんだよね。

gitbook watch がほしいとおもったけど見つからないので、 しかし、gitbook-cli は開発終わってる。

仕方ないので、gitbook watch 代わりにgulp watch を作ってみた。

gitbook はWEBサービスになっちゃったんだけど、なんか残念だよね。

gitbook-cli のビルド部分だけを gulp 化したもの

var gulp = require("gulp");


gulp.task('watch', function(done){

  gulp.watch(['**/*.md'], gulp.task('book'));

});


gulp.task('book', function( done ){
  // ./node_modules/.bin/gitbook から抜粋
  var parsedArgv = require('optimist').argv;
  var color = require('bash-color');
  var manager = require('./node_modules/gitbook-cli/lib');
  var commands = require('./node_modules/gitbook-cli/lib/commands');
  var program = require('commander');
  var bookRoot = parsedArgv._[1] || process.cwd();

  function runPromise(p) {
    return p
      .then(function() {
        process.exit(0);
      }, function(err) {
        console.log('');
        console.log(color.red(err.toString()));
        if (program.debug || process.env.DEBUG) console.log(err.stack || '');
        process.exit(1);
      });
  }
  return manager.ensureAndLoad(bookRoot,program.gitbook)
    .then(function ( gitbook ) {
      return commands.exec(gitbook.commands, 'build', [], [])
    });
});

ハードウェアの情報を一覧する lshw コマンド

ハードウェアの情報を収集して出力する

lsusb や lspci などのコマンドがあるけど、まとめて実行して情報を取り出すには不便。調べたら lshw といういうコマンドを見つけた

インストール

takuya@:~$ sudo apt search lshw
ソート中... 完了
全文検索... 完了
lshw/stable 02.18-0.1 amd64
  ハードウェア設定に関する情報

lshw-gtk/stable 02.18-0.1 amd64
  ハードウェア構成に関する情報をグラフィカルに表示

python3-checkbox-support/stable 0.22-1 all
  collection of Python modules used by PlainBox providers

takuya@:~$ sudo apt instal  lshw

使い方

sudo をつけてコマンドを実行すると良い。 htmlやXMLで取得することも可能だ。

takuya@:~$ sudo lshw -h
Hardware Lister (lshw) - unknown
usage: lshw [-format] [-options ...]
       lshw -version

    -version        print program version (unknown)

format can be
    -html           output hardware tree as HTML
    -xml            output hardware tree as XML
    -short          output hardware paths
    -businfo        output bus information

options can be
    -class CLASS    only show a certain class of hardware
    -C CLASS        same as '-class CLASS'
    -c CLASS        same as '-class CLASS'
    -disable TEST   disable a test (like pci, isapnp, cpuid, etc. )
    -enable TEST    enable a test (like pci, isapnp, cpuid, etc. )
    -quiet          don't display status
    -sanitize       sanitize output (remove sensitive information like serial numbers, etc.)
    -numeric        output numeric IDs (for PCI, USB, etc.)
    -notime         exclude volatile attributes (timestamps) from output

実行例

そのまま実行すると出力が大きすぎなので、ターミナルで実行するときは -short オプションがおすすめ

takuya@:~$ sudo lshw  -short
H/W path         デバイス     クラス      詳細
=======================================================
                                  system         To Be Filled By O.E.M. (To Be Filled By O.E.M.)
/0                                bus            J5005-ITX
/0/0                              memory         64KiB BIOS
/0/b                              memory         8GiB システムメモリー
/0/b/0                            memory         8GiB SODIMM DDR4 同期 2400 MHz (0.4 ns)
/0/b/1                            memory         DIMM DDR2 同期 [空]
/0/15                             memory         224KiB L1 キャッシュ
/0/16                             memory         4MiB L2 キャッシュ
/0/17                             processor      Intel(R) Pentium(R) Silver J5005 CPU @ 1.50GHz
/0/100                            bridge         Intel Corporation
/0/100/0.1                        generic        Intel Corporation
/0/100/2                          display        Intel Corporation
/0/100/e                          multimedia     Intel Corporation
/0/100/f                          communication  Intel Corporation
/0/100/12                         storage        Intel Corporation
/0/100/13                         bridge         Intel Corporation
/0/100/13.1                       bridge         Intel Corporation
/0/100/13.2                       bridge         Intel Corporation
/0/100/13.2/0    enp3s0           network        RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller
/0/100/13.3                       bridge         Intel Corporation
/0/100/13.3/0                     storage        ASM1062 Serial ATA Controller
/0/100/15                         bus            Intel Corporation
/0/100/15/0      usb1             bus            xHCI Host Controller
/0/100/15/0/3                     generic        802.11n WLAN Adapter
/0/100/15/0/5                     communication  BT2.0
/0/100/15/0/6                     bus            NEC USB HUB (ASC)
/0/100/15/0/6/1                   input          109 JPN USB KBD (ASC)
/0/100/15/0/6/3                   input          wireless dongle
/0/100/15/1      usb2             bus            xHCI Host Controller
/0/100/1f                         bridge         Intel Corporation
/0/100/1f.1                       bus            Intel Corporation
/0/1             scsi0            storage        
/0/1/0.0.0       /dev/sda         disk           240GB ADATA SP550
/0/1/0.0.0/1     /dev/sda1        volume         511MiB Windows FAT ボリューム
/0/1/0.0.0/2     /dev/sda2        volume         732MiB EXT4ボリューム
/0/1/0.0.0/3     /dev/sda3        volume         48GiB EFI partition
/0/1/0.0.0/4     /dev/sda4        volume         174GiB EXT4ボリューム
/1               vlan2            network        イーサネット interface
/2               vlan10           network        イーサネット interface
/3               vlan200          network        イーサネット interface
/4               vlan30           network        イーサネット interface
/5               wlx000b8181dc8e  network        無線インターフェース
takuya@:~$ 

if 文には必ずブロックをつけろと言われることが多いけど、使い方によってはむしろ邪魔

if にブロックがないと叱られたことが昔から多い。

if のブロックって上手に書けばいいと思うし、設定やLintで矯正されたりするんだけどさ。

この if の書き方を見ほしい

function setupAce(e, set){
  
  //デフォルト設定(カスタマイズしたい場合はの引数(set)に以下の様にセットして下さい。)
  if(!set) set = {
    theme:"chrome",  
    mode:"text",    
    options:{        //AceEditorOption設定類
      fontSize: "12px",
      maxLines: 30,
      minLines: 5,
      showInvisibles: true,
    },
    focus:false
  };

一見するとブロックがあるように見えるけど、ブロックは使ってなくて、初期化変数。

なかなかおもしろいよね。工夫次第でシンプルにわかりやすく記述はできるんだなと

laravel の api ルートを叩いてもloginページやHTMLが帰ってきてjson以外になってしまう場合

TL;DR

HTTPリクエストのヘッダに、 Accept: text/json が抜けている可能性が高い。

Laravelのレスポンスが login になる場合。

api で auth を入れているところへリクエスト投げつける。

HTMLのログインが帰ってくる。

実例

curl -H 'Content-Type: application/json' -F file='@/Users/takuya/Pictures/Dh6PcyQUYAEzhKp.jpg' http://127.0.0.1:8000/api/user/1/images/ 

* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
> POST /api/user/1/images/ HTTP/1.1
> Host: 127.0.0.1:8000
> Accept: */*
> Accept-Encoding: gzip, deflate, sdch
> User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36
> X-Config-File: ~/.curlrc
> Content-Length: 37112
> Content-Type: application/json; boundary=------------------------f7fa3a50954906f3
> Expect: 100-continue
>
* Done waiting for 100-continue
  0 37112    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0} [37112 bytes data]
* We are completely uploaded and fine
< HTTP/1.1 302 Found
< Host: 127.0.0.1:8000
< Date: Tue, 28 May 2019 14:57:15 +0000
< Connection: close
< X-Powered-By: PHP/7.3.4
< Cache-Control: no-cache, private
< Date: Tue, 28 May 2019 14:57:15 GMT
< Location: http://127.0.0.1:8000/login
< X-RateLimit-Limit: 60
< X-RateLimit-Remaining: 59
< Content-Type: text/html; charset=UTF-8
<
{ [352 bytes data]
100 37464    0   352  100 37112    272  28724  0:00:01  0:00:01 --:--:-- 28996
* Closing connection 0
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="0;url=http://127.0.0.1:8000/login" />

        <title>Redirecting to http://127.0.0.1:8000/login</title>
    </head>
    <body>
        Redirecting to <a href="http://127.0.0.1:8000/login">http://127.0.0.1:8000/login</a>.

同一ページに Accept-JSONを併せて送りつけた場合。

HTTPのヘッダにAcceptを入れると、401 がとJSONが返ってくる。

takuya@$ curl-json -H 'Content-Type: application/json' -F file='@/Users/takuya/Pictures/Dh6PcyQUYAEzhKp.jpg' http://127.0.0.1:8000/api/user/1/images/ 

> POST /api/user/1/images/ HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/7.65.0-DEV
> Accept: text/json
> X-Config-File: ~/.curlrc-json
> Content-Length: 37112
> Content-Type: text/json; boundary=------------------------4610ff915435cd7f
> Expect: 100-continue
>
* Done waiting for 100-continue
} [37112 bytes data]
* We are completely uploaded and fine
< HTTP/1.1 401 Unauthorized
< Host: 127.0.0.1:8000
< Date: Tue, 28 May 2019 14:54:59 +0000
< Connection: close
< X-Powered-By: PHP/7.3.4
< Cache-Control: no-cache, private
< Date: Tue, 28 May 2019 14:54:59 GMT
< Content-Type: application/json
< X-RateLimit-Limit: 60
< X-RateLimit-Remaining: 58
<
{ [30 bytes data]
* Closing connection 0
{"message":"Unauthenticated."}

laravel のAPIにリクエストを送付するときは

リクエストヘッダのAccept(クライアントが受け取りたいMIME形式の指定)でJSONを指定する必要がある。

Accept: text/json

これは、どこで定義されているのか

Accept をみてMIMEや認証は、どこのメソッドで定義されているのか。

vendor/laravel/framework/src/Illuminate/Http/Concerns/InteractsWithContentTypes.php#expectsJson
<?php
public function expectsJson()
    {
        return ($this->ajax() && ! $this->pjax() && $this->acceptsAnyContentType()) || $this->wantsJson();
    }

ここでリクエストのヘッダを見ている。HTTP/Requestで使える。

参考資料

https://github.com/laravel/framework/blob/5.8//src/Illuminate/Http/Concerns/InteractsWithContentTypes.php#L42

composer でgithub / gitlab などのgit レポジトリをコマンドから指定してインストール

php/composer でコマンドから git レポジトリをインストールしたい。

composer で git のレポジトリ(非公式 package / 自作pkg )を指定して追加して使いたい。

通常は composer.json を編集するのだろうけど、 jsonの手作業の編集は、苦痛。

なので、コマンドから指定して実行したら楽になる。

手順

  • composer.json に config を追加
  • composer install

composer.jsonに git(vcs)を追加する。

composer config コマンドを使って、git でアクセス可能なレポジトリを追加します。

composer  config repositories.my-helpers vcs ssh://git@example.com/takuya/my-helpers.git

これで、json ファイルができた。

composer install します。

vcs を参照するようになったら、require に登録してインストールします。

composer require --dev  takuya/my-helpers:master
composer install

レポジトリ名はURLから github.com/takuya/my-repos のような構造からパスを取り出して、ブランチを指定する。

これでミスなく手軽になる。composer で自作の非公開のパッケージを自動的に取り込む構成が作れるので、dockerイメージや docker-compose でインストールのスクリプトを作るときなどに本当に楽になる。

関連資料

http://takuya-1st.hatenablog.jp/entry/2014/07/09/114736

参考資料

https://stackoverflow.com/questions/31743139/how-to-add-non-public-repositories-from-command-line-with-composer

JS で String#replaceAll すべて置換をするには

JS のコードレビューをしていて、気になってしょうがない split.join

いっぱい次のような、関数をいっぱい見かけるのですが、これは replaceAll の代りにし使ってるんだろうか。一般的なんだろうか。 どっかのサイトで上位に出てくるんだろうか。○iita とか

## これはやめてほしい。
update_date.split('-').join('');

正規表現で意図が明確コードを

正規表現のグローバルマッチを使うと良い。

update_date.replace( /-/g , '' );

置換はコールバックが便利

置換するなら、コールバックをすることが便利。

update_date.replace( /-/g ,  function( e ){   return e+'--'   } );

sshfs でFUSEマウントしたフォルダへの転送速度を測定した

sshfs でFUSEマウントしてみました。

sshfs は gvfs などネットワークフォルダとしてSSHを扱えるものですね。

sudo apt install sshfs

マウント

mkdir mnt
sshfs takuya@192.168.11.125:/home/takuya mnt

転送してみました。

takuya@:Desktop$ dd if=test.img of=mnt/test.img 
2000000+0 レコード入力
2000000+0 レコード出力
1024000000 bytes (1.0 GB, 977 MiB) copied, 116.963 s, 8.8 MB/s

やっぱりFUSEは速度でないですね。CPU周りの問題なんでしょうか

それでも gvfs よりは速いです。

gvfs でssh FUSEマウントしたファイルシステムの書き込みが遅い

gvfs でマウントしつかってて、どうも遅い。

速度測定してみた

あまりに遅いので、1GBの転送は途中で諦めてしまった。

takuya@:Desktop$ dd if=test.img of=/run/user/1000/gvfs/sftp:host=192.168.11.125/home/takuya/test.img
^C97031+0 レコード入力
97031+0 レコード出力
49679872 bytes (50 MB, 47 MiB) copied, 126.678 s, 392 kB/s

10MBで試した結果がこちらです。

takuya@:takuya$ dd if=/dev/urandom  of=test.img bs=1k count=10000
10000+0 レコード入力
10000+0 レコード出力
10240000 bytes (10 MB, 9.8 MiB) copied, 12.7177 s, 805 kB/s

なんどか試してみましたが、sftp は 1MB/s で、afp/smb は 3MB/s が限界でした。FUSEなのでマウントしてるLinuxクライアント側のメモリ量やCPU速度にも影響を受けますが、めっっちゃ遅いですね。

ssh の転送速度を測定をしてみる

SSHの速度を測定しようと思い立った。

なんかネットワークが遅いので、SSHでの速度測定をしてみることに。

速度測定するコマンド

ファイルの準備

dd if=/dev/urandom  of=test.img bs=1k count=1000000

転送

cat test.img  | ssh host.tld 'dd of=/dev/null '

ssh でパイプする

ssh でパイプするとファイル転送ができる。

cat test.img | ssh host ' cat - > test.img'

dd は of だけ指定すると標準入力

dd は if / of で指定するけど、標準入力からもととれる。

実際にやってみた例

takuya@:Desktop$ dd if=/dev/urandom  of=test.img bs=1k count=1000000
1000000+0 レコード入力
1000000+0 レコード出力
1024000000 bytes (1.0 GB, 977 MiB) copied, 39.8002 s, 25.7 MB/s
takuya@:Desktop$ cat test.img  | ssh myhost 'dd of=/dev/null '
sign_and_send_pubkey: signing failed: agent refused operation
2000000+0 レコード入力
2000000+0 レコード出力
1024000000 bytes (1.0 GB, 977 MiB) copied, 9.16781 s, 112 MB/s

ファイル書き込みがボトルネックになっていないか

先程の例は、純粋にネットワーク速度に近いものが出ているはず。ファイルに書き込んでみたいと思う

この場合は、ファイルIOがメモリキャッシュされないように結構な量を書き込む必要がある。たぶん3GBくらい

SSD 相手に書き込んだとき

takuya@:Desktop$ cat test.img  test.img test.img | ssh host.tld ' dd of=test.img'
sign_and_send_pubkey: signing failed: agent refused operation
6000000+0 レコード入力
6000000+0 レコード出力
3072000000 bytes (3.1 GB, 2.9 GiB) copied, 30.6751 s, 100 MB/s

HDDを相手に書き込んだとき

takuya@:Desktop$ cat test.img test.img test.img  | ssh host.tld ' dd of=./mount/96.作業用/test.img'
sign_and_send_pubkey: signing failed: agent refused operation
6000000+0 レコード入力
6000000+0 レコード出力
3072000000 bytes (3.1 GB, 2.9 GiB) copied, 35.9622 s, 85.4 MB/s

メモリキャッシュがきいてる気もする。が、まぁ実際に使ってる速度に近い測定結果ナノではないでしょうか。

あくまで概算

ssh は圧縮されたりするので、本当のネットワークの速度よりも若干高くなる。 /dev/urandom を使うことで圧縮されないようにはしてるけど。

我が家の環境では 111 MB/s でているようである。

ところが、Samba経由したり WebDAV 経由すると 3MB/s くらいしかでない。こまった。

curl でもできる

curl を使ってもできる

これはSFTPで速度測定になる。

takuya@:~$ curl sftp://192.168.11.125/home/takuya/test.img > /dev/null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 2929M  100 2929M    0     0  42.3M      0  0:01:09  0:01:09 --:--:-- 44.0M
100 2929M  100 2929M    0     0  42.3M      0  0:01:09  0:01:09 --:--:-- 42.3M

/dev/urandom の速度

ちなみに、/dev/uramdom でdd したときの速度が 25MB/s 程度のCPUで測定しました

gvfs あたらめ gio でログインしたときだけネットワークのドライブをマウントする

Ubuntu のGVSマウントをログイン時にしたい。

ubuntu デスクトップのログイン時のマウント機能と同等のマウントしたい

fstab や autofs でもできるが、そっちはシステム全体なのでわかりやす。gvfs は面倒かと思ったけど、使ってみたらgvfs が圧倒的に楽だったのでメモ。

管理の側面から考えると、ログイン時にマウントされる方が嬉しいし。そもそもmount でマウントポイントが見れないのでいいかな

これを使うメリット

ネットワークの越しのマウントに、root 権限も、マウントポイントも要らないので、mountコマンド初心者でも使いやすい。

gvfs とは

最近は gio という名前になっているようです。

いろいろな、ネットワークのドライブをFUSEでマウントしてくれたりする。Ubuntuだと次の「アカウントの追加」で追加設定したストレージに使われている。

f:id:takuya_1st:20190520162638p:plain:w200

実際にマウントされたら次のようになる。左の柱に出てくるネットワークの場所ですね。

f:id:takuya_1st:20190520162721p:plain:w200

gvfs はマウントポイントがわかりにくい

gvfs でマウントされている

gvfs-mount -l

これは、mountで出てくる。けど分かりにくいかもしれません。

takuya@:~$ mount | grep gvfs
gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)
takuya@:~$ 

ちなみに、gvs-mount はいまは gio を使う

gio moout -l 

gio/gvfs でネットワークをマウントしてみる。

gio mount "cifs://takuya@my-nas/takuya's%20home/"

他にも、SSHフォルダをSFTPでマウントするには。

gio mount "ssh://takuya@my-sftp-server/"

などと、URLでプロトコルを指定してマウントしFUSEとして使えるのでめっちゃ便利。あれ、もうローカルにストレージが要らなくね?

など手軽にマウントできるじゃん。

GUI ツールで管理できる。

gigoloという管理ツールがありました。

sudo apt install gigolo

f:id:takuya_1st:20190520163613p:plain

gigoloGUIで管理できる。いいじゃん gigolo

これ使えば、システム全体に関係なくマウントできるから、ルート権限もいらないしめっちゃ楽じゃん

f:id:takuya_1st:20190520163626p:plain

ログイン時に自動的に接続したい

touch ~/MountAtLogin.sh
chmod +x  ~/MountAtLogin.sh

ファイルの中身を書く

## ~/MountAtLogin.sh
gio mount ssh:takuya@my-server/

最後に

Ubuntu自動起動するアプリケーション に登録して終了

これで、ログイン時に再接続されるのでWindowsのネットワーク・ドライブのような運用ができる。便利。

2019-05-24 追記

手軽だけど、どうも速度が遅く、HDMIキャプチャの録画ファイルの保存に失敗しているようである。そこで速度測定してみました

どうも、gvfs でマウントしたドライブはFUSEの呼び出しループの中で、CPU処理に影響を多分に受けていると思われる。

あまり多量のファイルを扱うのは得策でないと思う。

参考資料

wordpress をniginx のリバースプロキシの背後に設置した場合の mixed contents 対策

nginx の背後に wordpress を設置したら mixed content

wordpress を設置したんだけど、 .htaccess も使いたいと言われて、nginx から apache+php-fpm にリバースプロキシをした。するとhttp/https混在コンテンツになってしまった。

対策。

nginx → apache で リバースプロキシするさい X-Forwarded-Proto を追加する。

nginx 側

     proxy_set_header X-Forwarded-Proto https;

nginx などリバースプロキシでhttpsだとメモを残してヘッダにつけて送る(今回は HTTP_X_FORWARDED_PROTO  を使う)

wordpress 側 wp-config.php

<php
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'){
  $_SERVER['HTTPS']='on';
  }

HTTP_X_FORWARDED_PROTOをphp 側で受け取って HTTPS 変数を上書きする。

その他の対策方法

  • nginx → apache2 のリバースプロキシをオレオレ証明書https でやるとか。
  • apache2→ php-fpm で構成して apache2 から https だよと宣言するとか

まぁいろいろと考えられるけど、一番手っ取り早いのは wp-config.php を弄ることだった。

これは、CloudflareやAWS ELB などでHTTPSをONにした場合にも同じことが言える。

chrome の開発ツールのConsoleの履歴を消す。

Chrome の devtool の履歴を消す方法。

ChromeのJSコンソールに、パスワードとか直書きで書いてしまったときに。

パソコン本体にロックが掛かるようにしておけば全く問題ないのだけれど、画面共有中にうっかり誰かに見られても困るだろうし。

履歴を消すには、右クリック

f:id:takuya_1st:20190516201309p:plain
me

昔は、もっとめんどくさかったのに。簡単になってるのでメモ

動的に複数script を追加したときに読み込みを待つ。Promise版(body/headに足したあと待つ)

JS で動的ロードして関数を追加する。

適当な関数を突っ込んで、ロードされるのを待ってから、関数を使いたい。 とりあえず、script.onload で解決することはわかってるんだけど。読み込みたい関数が複数だと、全部ロードされるのを待つのをコールバック・チェーンで待つのはしんどかったので、Promise.allにした。

外部JSを追加してロード待つ

document に script タグを動的に追加して、onload 関数を仕込む。それをPromiseにして、複数のURLが全部ロード終わってResolveされるまでを、Promise.all()で待つ。

function import_script( urls ){
  return Promise.all( urls.map(function(url){return new Promise(function(resolve,reject){
    var script = document.createElement('script');
    script.src = url;
    script.onload=resolve;
    document.head.appendChild(script);
  })}));
}

ロード待ってからなにかする。

import_script( ["https://example.com/example.js", "https://example.com/example2.js"] ).then(function(){
  // main 
  console.log('loaded');
 // ここにロード後に実行したい処理を書く。
})

なんでこんな事やってるのか?

「babel とか webpackでトランスパイラすりゃいいじゃん?」

違うんだ、そうじゃないんだフロント開発じゃないんだ。

Chrome拡張で、メインページにスクリプトをInjectして追加したいとか。Bookmarkletでページにスクリプトを追加してなにかやりたいとか。

そういうときに足りないライブラリや、ショートカット関数を追加したい時があるんですね。

関連資料

気づいたら、ずっとおなじようなことやってんだww私はwww「まるで成長してない」

sed で数字の繰り返しを正規表現で置換するには、文字指定が違う

sed で数値指定する

数字のマッチは、次のようになる。

sed '/[[:digit:]]/'
sed '/[0-9]/'

正規表現に親しんでいると、つぎように \d を書きたくなるが、これは動かない。

sed '/\d/'  # 動かない。

sed で複数桁の数字にマッチさせる。

動かない

sed '/[[:digit:]]+/'

動く

sed '/[[:digit:]]\+/'

元データ:サンプル

nl とfor を使ってぱぱっとデータを作ります。

takuya@bookmarklets$ for e in aaa bbb ccc ; do echo $e; done | nl
     1  aaa
     2  bbb
     3  ccc

sed で行頭の数字を置換してみます。

行番号を sed コマンドで除去を試みてみます。

takuya@bookmarklets$ for e in aaa bbb ccc ; do echo $e; done | nl |  sed  's/[[:digit:]]\+\s\+//g'
     aaa
     bbb
     ccc
takuya@bookmarklets$ for e in aaa bbb ccc ; do echo $e; done | nl |  sed  's/[0-9]\+\s\+//g'
     aaa
     bbb
     ccc
takuya@bookmarklets$ for e in aaa bbb ccc ; do echo $e; done | nl |  sed  's/\d\+\s\+//g'
     1  aaa
     2  bbb
     3  ccc

まとめ

  • \d は動かないので [[:digit:]] or [0-9] を使う
  • + は解釈されないので \+ を使う。

この辺は ed / vi の置換に似てるね。

ちなみに、私が使っているのは gsed ( gnu sed ) です。

2019-05-16 追記

gsed

参考資料

regex - How to match digits followed by a dot using sed? - Super User

sed 文字列が含まれる行を削除する

sed で、文字列を探し、文字列が見つかった行を消す。

sed -e '/search/d'

検索語 search を含む行を削除。 これで指定文字列を探してその行を除去することができる。

行をまるごと消すのに、改行コードは必要ない。

ありがちなミス。

sed  's/search\n//' ## これはうまくいかない

改行コードを送るはめんどくさい。なぜなら、sedは1行ずつ処理することが前提だからだ。

コマンドの動作サンプル

3行のテキストサンプルを作ります。

for e in aaa bbb ccc ; do echo $e ;done  | nl
     1  aaa
     2  bbb
     3  ccc

ここから bbb にマッチする行を消してみます。

for e in aaa bbb ccc ; do echo $e ;done  | nl | sed -e '/bbb/d'
     1  aaa
     3  ccc

f:id:takuya_1st:20190515173803p:plain

使用例: sudo reboot を削除する。

コマンドの履歴から。sudo reboot を探してコマンド履歴をきれいにする。 reboot が履歴検索で暴発したらめんどくさいので。

cat .bash_history  | sed  -e '/^sudo reboot/d'  

ちゃんと消えているか確認。

cat .bash_history  | sed  -e '/sudo reboot/d'  |  grep 'sudo reboot' | wc -l 
0

awkperl / ruby などでもできるが。

sed が一番手っ取り早いし、sed で置換と行削除を覚えておくと捗りそうですよね。

てか、ゴミデータが混じったときに行ごと削除するのは、めっちゃ使うんで丸暗記してもいいくらい

参考資料

https://qiita.com/takech9203/items/b96eff5773ce9d9cc9b3