技術メモ、Tips、忘備録

技術系のメモ、試してみたこと、その他

これだけ知っておけばgitには困らない

これだけ知っておけばgitには困らない

普通に開発する分ならここに記載したコマンド群(オプション含め)で大抵のことは事足りると思います。

随時更新予定 更新日 2022/11/23

想定環境

OS: windows  
git version 2.37.3.windows.1  
remote: github  
github-flowを使用(forkしてPull Requestする運用方法)  
github-cliを使用(ただし別に使わなくても良い)  
コマンドプロンプト(cmd.exe)での使用  

git設定編

gitの設定がlocal,global,systemの3つの階層があることは重要なので理解しておいでください。
※私は基本的にlocalとglobalしかいじりません。

user, mail設定

コマンドでも可能ですが、私は設定ファイルを直接いじることが多いです。
1. %userprofile%\.gitconfigを開く(ファイルがなければ作成する 文字コード: utf8
2. 以下の通り追加

[user]  
    name = user_username  
    email = user_email@mail.com  

自動改行を無効か

デフォルトだとpullとかpushとかしたときにgitが勝手に改行コードをOSに合わせて変更するようになっているので、それを無効化します。
(つまりgitが勝手に改行コードを変更したりしなくなります)

[core]  
    autoCRLF = false  

エディタの設定

デフォルトだとviになっているので、使い慣れたエディタに変更する。
※私はサクラエディタを使います。
※exeファイルへの絶対パスを指定するか、パスを通している場合は以下のように実行ファイル名のみの指定も可能。

[core]  
    editor = sakura  

ssh鍵の作成、登録

  1. 公開鍵、秘密鍵の作成
$ssh-keygen -t ecdsa  
C:\develop\WHAT_IS\what_is_help>ssh-keygen -t ecdsa  
Generating public/private ecdsa key pair.  
Enter file in which to save the key (C:\Users\user_name/.ssh/id_ecdsa): #何も入力せずEnter  
Enter passphrase (empty for no passphrase): #何も入力せずEnter  
Enter same passphrase again: #何も入力せずEnter  
Your identification has been saved in C:\Users\user_name/.ssh/id_ecdsa. #こっちが秘密鍵  
Your public key has been saved in C:\Users\user_name/.ssh/id_ecdsa.pub. #こっちが公開鍵   
The key fingerprint is:  
SHA256:gdskjgijsidjsjie545as4d5g4asg user_name@HOSTNAME  
The key's randomart image is:  
+---[ECDSA 256]---+  
|o+      o+.      |  
|+ +    o =+.     |  
+----[SHA256]-----+  
  1. githubに公開鍵を登録
    github.comにログインし、settingsSSH and GPG keysnew SSH Key
    title: 任意の名前を登録(例えばPCのホスト名とか)
    key type: Authentication Key
    Key: 先ほど作成したキー(C:\Users\user_name/.ssh/id_ecdsa.pub)をテキストエディタで開き、中身をコピーして貼り付け
    [Add SSH Key]押下

これでgithubSSH接続が可能です(要するにpushとかできるようになる)

TortoiseGitの場合

  1. TortoiseGit\bin\puttygen.exeを実行
  2. Generate⇒枠内でマウスを適当に動かすと鍵が作成される。
  3. [Save public key]押下⇒C:\Users\user_name/.ssh/tortoise_puttyに保存
  4. [Save public key]押下⇒C:\Users\user_name/.ssh/tortoise_putty.ppkに保存
  5. githubに公開鍵を登録 ※登録手順は上記の「githubに公開鍵を登録」と同様 ※C:\Users\user_name/.ssh/tortoise_puttyの中身をgithubに登録
  6. Pagentに登録
cd TortoiseGit\bin  
pageant.exe "C:\Users\user_name\.ssh\for_tortoise_git.ppk"  

これでTortoiseGitを使用してgithubSSH接続が可能です(要するにTortoiseGitでpushとかできるようになる)

運用編

Fork

こちらを使っていきます。
https://github.com/monkey999por/TestRep
github上で操作フォークしたいリポジトリでforkボタン押下⇒[Create fork]
これで自分のリポジトリにフォークが作成されます。

git clone

$git clone git@github.com:monkey999por-sub/TestRep.git  
$cd TestRep  

upstreamの設定、確認(git remote add upstream $URL)

$git remote add upstream https://github.com/monkey999por/TestRep.git  
#正しく設定されているか確認  
#origin: forkしたリポジトリ  
#upstream: fork元のリポジトリ  
$git remote -v  
origin  git@github.com:monkey999por-sub/TestRep.git (fetch)  
origin  git@github.com:monkey999por-sub/TestRep.git (push)  
upstream        https://github.com/monkey999por/TestRep.git (fetch)  
upstream        https://github.com/monkey999por/TestRep.git (push)  
  
#リモートブランチの確認 origin/mainとupstream/mainがあればOK  
$git fetch -p upstream  
$git branch --remote  
  origin/HEAD -> origin/main  
  origin/main  
  upstream/main  
  

ローカルブランチの作成、originへの紐づけ(git checkout -b develop, git push -u origin develop)

$git checkout -b develop  
Switched to a new branch 'develop'  
  
$git push -u origin develop  
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0  
remote:  
remote: Create a pull request for 'develop' on GitHub by visiting:  
remote:      https://github.com/monkey999por-sub/TestRep/pull/new/develop  
remote:  
To github.com:monkey999por-sub/TestRep.git  
 * [new branch]      develop -> develop  
branch 'develop' set up to track 'origin/develop'.  
  
#ちゃんと紐づいているか確認  
$git branch -vv  
* develop 4f11259 [origin/develop] comment  
  

すでにoriginにブランチが存在する場合は、以下のように設定することも可能

$git branch -u origin/develop develop  
branch 'develop' set up to track 'origin/develop'.  

commit, push (git commit -m "comment", git push)

$git add .  
$git commit -m "originで追加"  
$git push   

upstraemの更新を取得(=originを最新化)(git fetch -p upstream, git merge upstream/develop)

#upstreamの更新情報を取得  
$git fetch -p upstream  
  
#自分のローカルブランチにupstreamを取り込み  
$git merge upstream/main  
Auto-merging file.txt  
CONFLICT (content): Merge conflict in file.txt  
Automatic merge failed; fix conflicts and then commit the result.  

あらら、コンフリクトしちゃいました。↓

コンフリクトの解消 (解消後にmerge commit)

#状況確認  
$git status  
On branch develop  
Your branch is up to date with 'origin/develop'.  
  
You have unmerged paths.  
  (fix conflicts and run "git commit")  
  (use "git merge --abort" to abort the merge)  
  
Unmerged paths:  
  (use "git add <file>..." to mark resolution)  
        both modified:   file.txt #これがコンフリクトしてる  
          

コンフリクトしているファイルを開き、修正する。

<<<<<<< HEAD  
  
originで追加したもの  
  
=======  
  
upstreamで追加されていたもの  
  
>>>>>>> upstream/main  

<<<<<<< HEAD=======の間: HEADから追加しようとした行
=======>>>>>>> upstream/mainの間: upstream/mainで追加されていた行

修正方法としては<<<...===...>>>...を削除して、中身をいい感じに結合なり書き換えなりします。今回はどちらも残すようにしました。

修正後  
originで追加したもの  
upstreamで追加されていたもの  

コミットする

$git add file.txt  
$git commit -m "merge commit"  
$git push   
$git l #git logにalias設定してます。詳細は後述  
*   [2022-11-20 6 minutes ago]  monkey999por-sub        e94ec15  (HEAD -> develop, origin/develop)merge commit  
|\  
| * [2022-11-20 27 minutes ago]         monkey999por    61bc096  (upstream/main)upstreamで追加  
* | [2022-11-20 25 minutes ago]         monkey999por-sub        0974599 originで追加  

pull request作成(gh pr create)

$gh pr create  
? Which should be the base repository (used for e.g. querying issues) for this directory? monkey999por/TestRep  
# upstreamに設定したリポジトリを選択  
  
Creating pull request for monkey999por-sub:develop into main in monkey999por/TestRep  
  
? Title first pull request  
? Body <Received>  
? What's next? Submit  
https://github.com/monkey999por/TestRep/pull/1  

ここまでで基本的にやることは終わり

よく使うコマンド集

ブランチ削除(local: git branch -D develop , remote: git push -d origin develop)

ローカルブランチの削除

$git branch -d branch_name  

リモートブランチの削除

$git push -d origin branch_name  

ローカルブランチをupstreamの最新で更新

$git fetch -p upstream  
$git reset --hard upstream/branch_name  

commitの取り消し

$git commit -m "dummy commit" #間違えてコミットしちゃった  
#取り消し  
$git reset --mixed head~  

ブランチ存在確認

$git branch -a | find /i "branch_name"  

gitignoreが反映されない場合(キャッシュの削除)

こちらの記事が参考になります
https://qiita.com/fuwamaki/items/3ed021163e50beab7154

特定のファイルの変更を取り消す

$git checkout filename.txt  
  
#ワイルドカード指定も可能  
$git checkout *.txt  

変更したファイルの一覧(--name-only)

$git diff --name-only  

フォーマットしてログ出力(でもログの確認は基本的にトータスとか使う方が良いと思う)

$git log --graph --all --format='[%as %ah] %x09%C(cyan bold)%an%Creset%x09%C(yellow)%h%Creset %C(green reverse)%d%Creset%s' --branches  

aliasの設定

%userprofile%\.gitconfigにこんな感じで追記。

[alias]  
    a = add  
    b = branch  
    c = checkout  
    ch = cherry-pick  
    d = diff  
    rmh = reset --mixed head  
    rhh = reset --hard head  
    s = status  
    f = fetch  
    l = log --graph --all --format='[%as %ah] %x09%C(cyan bold)%an%Creset%x09%C(yellow)%h%Creset %C(green reverse)%d%Creset%s' --branches  

設定ファイルの場所

local: プロジェクトフォルダの中の.git/config
global: %userprofile%.gitconfig
system: インストールディレクトリのetc/gitconfig

それぞれ以下で開くこともできる

$git config --edit --local  
$git config --edit --global  
$git config --edit --system  

強制push(非推奨)

※ブランチの関係性が壊れる可能性があるのでよほどのことがない限り使わないように。

$git push -f   

変更の一時保存、取り出し(git stash save "comment", git stash list, git stash apply)

#ファイルを新規に作ったりしている場合は最初にステージングに乗せておく必要あり  
$git add .  
$git stash save "comment"  
  
#stashの確認  
$git stash list  
stash@{0}: On main: comment  
  
#stashの取り出し  
$git stash apply stash@{0}  
  
#stashの削除  
$git stash drop stash@{0}  
Dropped stash@{0} (88ecdc38b520e4f0b67a78bf18d1623606465964)  
  

なんか変なことになったらとりあえずこれでバックアップをとる

例えばupstream取り込みmergeしてコンフリクト置きまくったときとか。なれないと焦ると思うが、いったん以下のことだけしておけばバックアップはとれる。

#いったんすべてステージングに追加(新規追加したファイルとかもこれで対応可能)  
$git add .  
  
#stashに保存  
$git stash save "comment"  
  
#保存されていることを確認する  
$git stash list  
  
#upstreamの最新を取得  
$git fetch -p upstream main  
$git reset --hard upstream/main  
  
#stashを適用  
$git stash apply stash@{n} ※n  
  
#ここでコンフリクトの解消する  
  
#あとは普通にコミットしてPRの作成  
$git add .  
$git commit -m "merge commit"  
$git push   
$gh pr create  
  

helpの確認

$git comand -h  
  
#例  
$git status -h  
  
usage: git status [<options>] [--] <pathspec>...  
  
    -v, --verbose         be verbose  
    -s, --short           show status concisely  
    -b, --branch          show branch information  
    --show-stash          show stash information  
    --ahead-behind        compute full ahead/behind values  
    --porcelain[=<version>]  
                          machine-readable output  
    --long                show status in long format (default)  
    -z, --null            terminate entries with NUL  
    -u, --untracked-files[=<mode>]  
                          show untracked files, optional modes: all, normal, no. (Default: all)  
    --ignored[=<mode>]    show ignored files, optional modes: traditional, matching, no. (Default: traditional)  
    --ignore-submodules[=<when>]  
                          ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)  
    --column[=<style>]    list untracked files in columns  
    --no-renames          do not detect renames  
    -M, --find-renames[=<n>]  
                          detect renames, optionally set similarity index  

commit objectの指定方法いろいろ

head~              #headに対して1つ前のコミット  
head~~             #headに対して2つ前のコミット  
head~~~            #headに対して3つ前のコミット  
stash@{0}          #stashに保存したもの。使うことはないだろうけどここに対してcheckoutも可能  
6ed25aa            #logとかで確認可能なcommit hash  
-------  
branch             #ローカルブランチ  
origin/branch      #originのブランチ   
upstream/branch    #upstreamのブランチ   
tag                #タグ  

そのうち追記予定(そこまで使用頻度は高くないけどたまに使うものたち)

  • git submodule(前に使ったことあるけどたぶんそこまで使われてない?)
  • その他:gitのremoteリポジトリをローカル上に作成(git init --bare --sheard)(あと共有の設定)
  • プロキシの設定
  • 注意:パスワードに#等のbashエスケープが必要な文字は事前にエンコードしておく必要がある。
  • 文字化け対応(log, status)
  • コミットをまとめる(rebase -i)
  • tagの作成
  • 取り消しcommit(git revert)
  • 特定のコミットの取得(git cherry-pick)

【java】ファイルの作成、読み込み、書き込み、削除のやり方

ファイルの作成、読み込み、書き込み、削除のやり方

    static void fileOperation() throws IOException {

        // 作成
        // create file
        String filename = "C:\\temp\\file.txt";
        File outFile = new File(filename.toString());
        boolean ready = outFile.exists() && outFile.delete();
        if (ready)
            Files.createFile(Path.of(filename));

        // 書き込み
        FileWriter writer = new FileWriter(filename);
        String br = System.getProperty("line.separator");
        writer.write("aaaa" + br);
        writer.write("bbbb" + br);
        writer.write("cccc" + br);

        // バッファを書き込み 普通はcloseすれば書き込まれるから不要
        writer.flush();

        // 読み込み 全行
        String contents = Files.readString(Paths.get(filename));
        // aaaa
        // bbbb
        // cccc
        System.out.println(contents);

        // 読み込み 1文字
        FileReader fileReader = new FileReader(outFile, StandardCharsets.UTF_8);
        System.out.println(fileReader.read());// 一文字読み込み 97 ※aの文字コード

        // 読み込み 1行
        BufferedReader rowReader = new BufferedReader(fileReader);
        String content;
        while ((content = rowReader.readLine()) != null) {
            // aaa(※↑同じファイルに対してraedとかすると、その分はすでに読み込まれたことになるっぽい。なので↓の出力はaaa)
            // , bbbb, cccc
            System.out.println(content);
        }

        // try with resourceだとこんな感じ closeは不要
        try (FileReader f = new FileReader(filename);
             BufferedReader b = new BufferedReader(f)) {
            System.out.println(b.readLine()); // aaaa
        } catch (Exception e) {
        }

        // close
        try {
            writer.close();
        } catch (IOException e) {
            try {
                writer.close();
            } catch (Exception e1) {
            }
        }
    }

ES2015以降のclassやオブジェクトリテラルの記法

ES2015以降のclassやオブジェクトリテラルの記法

※今のとこ雑にしかまとめてないですがどんどん整理していきます。
概要

classは内部的にはfunction()のシンタクスシュガー
javascript本来のprototypeベースのオブジェクト指向を疑似的にclassで内包しているだけ
※ただしfunctionと違いclassは定義前には呼び出せない(要するにnew演算子はclass定義より後にしか使えない)




クラス(class), アクセサ(get,set)

class Member {
  // constructor
  constructor(value) {
    // field
    this.value = value;
  }

  // get accesser
  // _temp:内部的にのみ持つ一時的な変数。
  // valueにsetterで直接アクセスできないため、
  // setterでは_tempに値をセットしている。そのため、getterでも_tempを返す。
  // 一時変数名がなんでもよいことを明示的にするために名前を_tempとしているが、本来は_value(アンダースコア + アクセサ名)にすべき
  // こういうこと https://ginpen.com/2017/12/05/javascript-getter-setter/
  get value() {
    return `${this._temp} : call get`;
  }
  // set accesser
  // _temp:内部的にのみ持つ一時的な変数。
  // なぜvalueではなく_tempを返すのか?
  // ⇒仮にthis.value = valueとしてしまうと。this.valueにセットしようとした時点でset valueアクセサを介してしまう
  // ため、setが無限回呼ばれることになってしまう。
  set value(_temp) {
    this._temp = `${_temp} : call set`;
  }

  // static method
  static staticMethod() {
    console.log(`this is static method`);
  }

  // instance method
  someMethod() {
    return this.value;
  }
}
let m = new Member("aaa");
// ※以下のような結果になる理由
// 1. new Member('aaa'); ⇒これの中に定義してるthis.value = valueが
//     setter(set value)を呼ぶ
// 2. m.valueがgetter(get value)を呼ぶため
console.log(m.value); //"aaa : call set : call get"
console.log(m.someMethod()); // "aaa : call set : call get"
Member.staticMethod(); // "this is static method"

classを変数に入れることも可能

const Test = class {
  // 中身は同じ
};

継承(extends)

class Animal {
  constructor(value) {
    this.animalV = value;
  }
  getValue() {
    return `${this.animalV} (get with animal)`;
  }
  getAnimalValue() {
    return `${this.animalV} URYYYY`;
  }
}
class Cat extends Animal {
  constructor(animalV, value) {
    // 親コンストラクタ呼び出し
    super(animalV);
    this.catV = value;
  }
  // override
  getValue() {
    // 親のプロパティはthisでアクセス
    // 親のメソッドはsuperでアクセス
    return `${this.animalV} override by cat : ${
      this.catV
    } : ${super.getValue()}`;
  }
}
const cat = new Cat("あにまる", "ねーこ");
console.log(cat.getValue()); // "あにまる override by cat : ねーこ : あにまる (get with animal)"
console.log(cat.getAnimalValue()); // "あにまる URYYYY"

オブジェクトリテラル(object literal)

let objC = {
  firstName: "takashi",
  lastName: "honda",
  toString() {
    return `${this.firstName} : toString`;
  },
  oldFunc: () => {console.log('古い書き方');}
};
console.log(objC.toString()); // "takashi : toString"
objC.oldFunc(); // "古い書き方"

プロパティの動的生成

let i = 0;
let dynamicVars = {
  name: "test",
  ["a" + ++i]: "memo1",
  ["a" + ++i]: "memo2",
  ["a" + ++i]: "memo3",
};
console.log(dynamicVars.a1); // memo1
console.log(dynamicVars.a2); // memo2

モジュール(export/import)について

いろいろ書くよりこれ見るのが一番
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export




プライベート変数 (Private class fields)

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes/Private_class_fields

class ClassWithPrivateField {
  // private field
  #privateField;

  constructor() {
    this.#privateField = 42;
    //   delete this.#privateField;   // Syntax error
    //   this.#undeclaredField = 444; // Syntax error
  }
  getPrivateField() {
    return this.#privateField;
  }
}
//instance.#privateField === 42;   // Syntax error
const instance = new ClassWithPrivateField();
console.log(instance.getPrivateField()); // 42

イテレータ(Iterator)

例えばfor ofとかは内部的にこの仕組みを使ってる

const ary = [1, 2, 3];
const itr = ary[Symbol.iterator]();
let d;
while ((d = itr.next())) {
  if (d.done) break;
  console.log(d.value); // 1,2,3
}

もしiteratbleなクラスを自作したいならこういうのが参考になる
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols




ジェネレータ(Generator), yieldキーワード

function* myGen() {
  // function「*」でジェネレータになる
  let val = "aaa";
  yield val; // yield: myGenの呼び出しごとに処理を一時停止し、myGenが呼ばれると次のyieldまで実行される
  val += " add after";
  yield val;
  yield "ccc";
}

console.log(myGen().next().value); // aaa
for (const iterator of myGen()) {
  console.log(iterator); // "aaa","aaa add after","ccc"
}

// ### プロキシ(Proxy)
const dataP = {
  red: "赤色",
  yellow: "黄色",
};
const proxy = new Proxy(dataP, {
  get(target, prop) {
    console.log(target); // 対象のオブジェクト(=dataP) 例:{red: '赤色', yellow: '黄色'}
    console.log(prop); // 例:呼び出し側でproxy.redとした場合は、"red"
    return prop in target ? target[prop] : "?";
  },
});
console.log(proxy.red); // "赤色"
console.log(proxy.aaa); // "?"

proxy.blue = "青色";
console.log(proxy.blue); // "青色"

参考

https://www.amazon.co.jp/s?k=javascript+%E6%9C%AC%E6%A0%BC%E5%85%A5%E9%96%80&adgrpid=60120324664&gclid=Cj0KCQiApb2bBhDYARIsAChHC9twpeiPSkR1T6yzjpSE3YWpCYlYKT6C8yKAgBeg_xlhdVfOC-HIN9YaAiQ9EALw_wcB&hvadid=618553085031&hvdev=c&hvlocphy=1009221&hvnetw=g&hvqmt=e&hvrand=10456938282411633299&hvtargid=kwd-332716054270&hydadcr=27268_14598057&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_3eoosl5iqa_e

最近思うけどjavaのsetterがvoidなのって失敗だよなぁ

getterに関して思うこともありますが、それはまたいつか

javaのsetterメソッドって、こんな感じで自クラスを返した方が良かったんじゃないか?というお話


class Main {
    public static void main(String[] args) throws Exception {
        Sub sub = new Sub()
            .setValue1("1")
            .setValue2("2");
    }
}

class Sub{
    private String value1;
    private String value2;

    public Sub setValue1(String value1) {
        this.value1 = value1;
        return this;
    }

    public Sub setValue2(String value2) {
        this.value2 = value2;
        return this;
    }
}

そもそもsetterなのに自クラスを返すのは、メソッドの責任範囲がおかしいとか、
java Bean仕様に則ってないのでよくないとかいろいろあるとは思います。が、ですね

オブジェクト指向ってそもそも内包されているデータに対してメソッドで操作を行うものじゃないですか
だから、「setterを使った後は、今セットした値に対して、処理を行うメソッドを呼び出す」という操作は必ず発生すると思うのですね
逆に、setter呼んだのに何もしない、っていうのは無く、もしそんな状況があったとしたら多分設計がおかしいと思うのですよ

まあそんな根拠です。
setterはpublic void setXX()っていうのはもうデファクトスタンダードですし、Bean仕様なくらいなので今更どうすることもできないのですが

cmdでwhereして見つかったものののパスをクリップボードに保存したい

タイトル通りです
調べるのも面倒なので作りました。
何かと便利(意外とよく使う)
get.bat

@echo off
@chcp 65001 > nul

rem "パスが通ってるファイルのフォルダパスをクリップボードにコピーする"

if "%1"=="" (
    echo パスが通ってるファイルのフォルダパスをクリップボードにコピーする
    exit /B 0
)

where /Q %1

if "%ERRORLEVEL%"=="0" (
    setlocal ENABLEDELAYEDEXPANSION
        for /F "delims=" %%i in ('where %1') do (
            echo %%~dpi
            set /P <NUL="%%~dpi" | clip
        )
     endlocal
) else (
    echo ファイルが見つかりません
)

■動かしみる

C:\>echo dummy|clip

C:\>powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\> Get-Clipboard
dummy

PS C:\> exit

C:\>where sakura
C:\Program Files (x86)\sakura\sakura.exe

C:\>get sakura
C:\Program Files (x86)\sakura\

C:\>powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\> Get-Clipboard
C:\Program Files (x86)\sakura\
PS C:\>

バッチはオーバーヘッドが少ないのでやっぱりいいですね。 Powershellももう少し気楽に使えるようになることを願います。

コマンドプロンプトでtasklistのヘルプ見たら、日本語と英語で違ってた

※提供されている機能が違うという話ではなく、単に日本語版のヘルプの説明が間違ってたという話です

■比較
分かりづらいですが、日本語版の方はつづりを間違えています。このヘルプ通りにしても動きません。
f:id:monkey999por:20201030131728p:plain

こういうのって報告すべきなのかな。

【Ubuntu】rmとかmvとか直接使うの怖いからwindowsのごみ箱的なコマンド作った

できたものがこちら。
github.com

バックアップとってから削除 or 移動します。
少し説明しますと、

1.ファイル名に日付を付与して、もともとの階層がわかるようにしてバックアップ
2.対象の削除 or 移動
3.バックアップ後の表示

という感じです。

 #!/bin/bash

# like a windows dust box
# if delete file or directory, move dust box directory
function dust () {

    local here=$(pwd)
    if [ -z ${DUSTBOX} ]; then
        echo not defined '$DUSTBOX'
        return
    elif [ -z ${1} ]; then
        echo "it has no argument"
        echo "syntax: \$dust {File or Directory}"
        return
    fi
    
    #バックアップするパスを取得
    #echo $(dirname $(pwd)${1} |sed "s/^\///g")
    local backup_path=$(dirname ${1})
    for p in ${backup_path//\/ }; do
        cd $p
    done

    #バックアップ先ディレクトリ
    backup_path=${DUSTBOX}/$(pwd | sed "s/^\///g" )
    mkdir -p ${backup_path}

    #削除対象
    local remove_target="$(pwd)/$(basename ${1})"
    echo "remove target: ${remove_target}"
    
    # back up file name
    local bk_file_name="$(basename ${remove_target}_$(date "+%Y_%m_%d_%H_%M_%S"))"
    echo "back up: ${backup_path}/${bk_file_name}"

    if [ -h "${1}" ]; then
        cp --attributes-only "${1}" "${DUSTBOX}/"
        rm -f "${1}"
    elif [ -f "${remove_target}" ]; then
        cp -f "${remove_target}" "${backup_path}/${bk_file_name}"
        rm -f "${remove_target}"
    elif [ -d "${remove_target}" ]; then
        cp -rf "${remove_target}" "${backup_path}/${bk_file_name}"
        rm -r "${remove_target}"
    else 
        echo -e "can't delete this. it is not file or directory or symbolic link.\nuse \"rm\" command."
    fi
    echo -e "\n"
    tree ${backup_path}

    cd "${here}"

}

実行結果はこんな感じ
f:id:monkey999por:20201025221433p:plain

・免責事項

当方は、当記事にコンテンツを掲載するにあたって、その内容、機能等について細心の注意を払っておりますが、コンテンツの内容が正確であるかどうか、最新のものであるかどうか、安全なものであるか等について保証をするものではなく、何らの責任を負うものではありません。また、当方は通知することなく当記事に掲載した情報の訂正、修正、追加、中断、削除等をいつでも行うことができるものとします。また、当記事、またはコンテンツのご利用により、万一、ご利用者様に何らかの不都合や損害が発生したとしても、当方は何らの責任を負うものではありません。