[指令] Command Line 操作
keywords: zsh
, iterm2
, terminal
, linux
open -a [appToOpen] [fileName] # 指定特定應用程式開啟檔案
tail -f [filename] # 從結尾開始讀檔,並且持續監控變化
Linux Terminal Command Reference @ linux community
變數
\$PATH
所有能夠在 Terminal 中直接被執行的程式,都需要放在 $PATH
內,否則需要先指定到該程式所在的資料夾後才能執行。
echo $PATH
如果想要將其他路徑添加到 $PATH
中,可以在 .bash_profile
或 .zshrc
中使用:
- 在
PATH=""
後面使用$PATH
是為了把原本已有的PATH
保留下來,否則會覆蓋掉。 - 用
:
當作不同路徑的區隔
# .zshrc
export PATH="$PATH:~/my-scrips"
操作資料夾
cd <directory> # 切換目錄
pwd # 取得目前所在的位置
ls -alpt # 列出目前的檔案列表,搭配 -a(顯示隱藏檔), -l(顯示完整資訊),
# -p(顯示較清楚),-t(根據最後修改時間排序檔案)
ls | wc -l # 顯示檔案數量
mkdir <directory> # 建立新的目錄
mkdir -p ~/Library/a_folder # 即使 Library 資料夾不存在也直接建立到 a_folder
touch # 建立檔案
cp <file> <directory> # 複製檔案
cp index.html about.html # 把檔案 index.html 複製一份成 about.html
cp -r a_folder b_bolder # 把 a_folder 資料夾複製進去 b_folder 資料夾中
mv <file-old> <file-new|directory> # 移動檔案
mv index.html info.html # 把檔案 index.html 更名成 info.html(重新命名、改名)
mv index.html a_folder/ # 把 index.html 移動到 a_folder 資料夾中
rm <file|directory> # 刪除檔案
rm *.html # 刪除目錄中的所有 html
rm -r <folder> # 刪除整個 a_folder
rm -f <file> # 刪除檔案
rm -rf [folder_name] # 刪除資料夾(不論裡面有沒有內容或其他資料夾)
sudo # 暫時取得權限
改變資料與檔案權限 chmod
$ chmod 644 * # 檔案用 644
$ chmod 755 * # 目錄用 755
# 一次修改因為檔案權限修改後,使得 git 認為檔案不同的情況
$ git ls-files -m | xargs chmod 644
# 一次修改所有資料夾底下的檔案或檔案
$ find YOUR_PATH -type d | xargs chmod 755
$ find YOUR_PATH -type f | xargs chmod 644
$ sudo find /path/to/dir -type f -exec chmod 0664 {} \; # 如果上一行出現錯誤,可試試這行
補充:
# 文件的權限類型
rwx = 111 = 7
rw- = 110 = 6
r-x = 101 = 5
r-- = 100 = 4
-wx = 011 = 3
-w- = 010 = 2
--x = 001 = 1
--- = 000 = 0
# 文件所屬群組
<擁有者> - <群組> - <其它>
讀取檔案
cat <file> # 將檔案內容輸出在終端機上
less <file> # 使用分頁的方式顯示內容
head <file> # 只顯示檔案的前 10 行
man open # 查看 open 指令說明
open # 開啟檔案
open -a [appToOpen] [fileName] # 指定特定應用程式開啟檔案
寫入檔案
# <cmd> > <file> # 將 <cmd> 的內容寫入 <file>
echo "my content" > my_file.rb # 取代原本的檔案內容
# <cmd> >> <file> # 將 <cmd> 的內容添加到 <file>
echo "my content" >> my_file.rb # 添加到原本的檔案內容
找檔案
# 尋找空檔案
$ find . -empty
# 尋找名稱後綴為 .del 的資料夾
# -iname 表示 case insensitive
# -type 表示要資料夾(directory)或檔案(file)
$ find . -iname '*.del' -type d
# 尋找名稱後綴為 .del 的檔案
$ find . -iname '*.del' -type f
# 尋找名稱副檔名為 .tsx 的檔案,但不要找 node_modules 裡的
$ find . -type f -name '*.tsx' ! -path "./node_modules/*"
找檔案中的內容
$ grep -ir '<content-to-find>' '<folder-path>'
# i: case-insensitive
# r: recursive
# l: 只顯示資料夾
$ grep -irl 'foobar' . # 從當前目錄開始找
剪貼簿(clipboard)
keywords: pbcopy
, pbpaste
# 複製
$ git diff | pbcopy # 將 stdout 的結果複製到剪貼簿
$ pbcopy < tsconfig.json # 將檔案內容複製到剪貼簿
# 貼上
$ pbpaste > foo.json # 將剪貼簿的內容貼到檔案內
glob
如果好奇該 glob 會匹配到的檔案有哪些,可以使用 echo
查看,例如:
echo (styles|constants)/**/dist # 在 styles 或 constants 資料夾內的 dist
echo packages/*
asterisk
What is the ** glob character? @ StackOverflow
使用單一個星號(single asterisk),可以用來匹配一層內的資料夾,例如 /x/*/y
可以匹配到:
/x/a/y
/x/b/y
但如果是使用雙個星號(double asterisk),則會以 recursive 的方式匹配,例如 /x/**/y
可以匹配到:
/x/any/number/of/levels/y
同時,如果不只是資料夾,還要針對特定副檔名時,可以這樣寫:
const path = [
'*.js', // 該層內所有副檔名為 .js 檔案(不管檔名)
'index.*', // 該層內所有檔名為 index 的檔案(不管副檔名)
'packages/*', // packages 下一層內的所有檔案
'packages/*/*.json', // packages/b/package.json
// packages/a/package.json
'packages/**/*.json', // packages/a/node_modules/lodash/package.json
// packages/a/node_modules/the-answer/package.json
// packages/a/package-lock.json
// packages/a/package.json
// packages/b/package.json
'packages/**/*', // packages 內的所有檔案
'src/index.js', // 一定要是 src/index.js
'src/js/*.js', // 匹配到 src/js/ 裡的所有 .js
'src/js/**/*.js', // 匹配到 src/js/any/number/of/level/ 裡的所有 .js
];
其他指令
clear # 清除畫面
history # 檢視 terminal 紀錄
history | grep migration # 搜尋含有 "migration" 的紀錄
輸入多行的 command 時,在每一行的最後使用 \
或 `,最後一行則不要輸。
=> bin/rails generate scaffold Product \
title: string description:text image_url:string price:decimal
使用 &&
可以一次執行兩個指令:
cd ~/Projects/Backup && node index.js
讓程序在背景執行
keywords: background
, bg
, fg
$ scrpcy # 執行某個程序
CTRL + Z # 按下
$ bg # 進入背景
$ jobs # 列出所有在背景的程序
$ fg n # 將第 n 個程序移回前景執行(n 可以用 jobs 看)
重新載入設定檔
keywords: source
source ~/.zshrc
看目前的 port 被誰佔住
# 查看 port 被誰佔住
lsof -wni tcp:3000
lsof -i tcp:3000
# 把那個 port 刪掉
kill -9 <pid>
列出系統執行的程序
ps aux # show me all running process
ps aux | grep ssh # 列出正在執行 ssh 的程序
killall node # 刪除所有正在執行的 node 程序
複製內容到剪貼簿
keywords: pasteboard
, pbcopy
# paste board
git diff | pbcopy. # 將 git diff 的結果複製到剪貼簿
# pbpaste 可以貼上
壓縮與解壓縮檔案(zip and unzip)
壓縮
# zip -r <output-file> <input-file>
$ zip -r function.zip . # 將該資料夾內的所有檔案壓縮為 function.zip
$ zip -9 -r --exclude="*.git*" function.zip . # 忽略掉 .git 資料夾內的檔案
$ zip -9 -r function.zip . -x '*.git*' '*.vscode*' # 忽略掉兩個以上的檔案
解壓縮
unzip -a file.zip -d /home/phpini
壓縮與打包檔案(tar)
# 查看 tar 指令
$ man tar
# 建立壓縮檔
# -z:使用 gzip 壓縮檔案
# -c:create
# -f:location of archived
# -P:--absolute-paths
tar -zcf node_modules.tar.gz -P /app/node_modules/
# 解壓縮
tar -xf node_modules.tar.gz
印出資料夾結構(print file tree)
Tree @ Manned
安裝:
$ brew install tree
使用:
# -a 印出所有檔案(包含隱藏檔)
# -d 只印出資料夾
# -L 2 只深入到第二層
# -C 顯示顏色
# -P node_modules 只列出符合 node_modules pattern 的檔案
# -I node_modules 忽略掉符合 node_modules pattern 的檔案
# -f 列出檔案的 full path
# --gitignore 使用 .gitignore
# --ignore-case 忽略大小寫
# --prune 不要顯示沒有對應檔案的資料夾
# 列出兩層的資料夾
$ tree . -d -L 2 -I node_modules --gitignore
# 列出有 *.tsx 在內的資料夾(搭配 -d 會有點故障)
$ tree -P "*.tsx" . --gitignore --prune
切換 MacOS 中預設的 Shell
修改 Terminal 預設的 Shell
在 MacOS 中預設的 Shell 是 bash
,打開 MacOS 的 Terminal,進入「偏好設定」--> 「一般」--> 「打開 shell 的設定」:
- zsh:
/usr/local/bin/zsh
- bash:
/bin/bash
修改使用者預設的 Shell
如果要使用指令更改預設的 shell 可以使用 chsh
指令,這種方式會同時改變使用 iTerm 等登入時預設的 Shell:
chsh -s /bin/zsh
常見問題
使用 source 和直接執行某個 script 檔的差別
What is the difference between executing a Bash script vs sourcing it? @ StackOverflow
如同 stack overflow 上的解答所說,不論是使用 source
或直接執行(execute)某個 script 檔,這些檔案中的內容都會被逐行執行,差別在於檔案中所定義的變數是否會暴露到當前的 shell 中:
- 使用 source 的話,檔案中所定義的變數或函式都會進到當前的 shell 中,即使檔案執行結束後,還是可以在 shell 中呼叫到該函式或檔案
- 使用 execute 的話,一旦檔案執行結束後,該檔案中所定義的變數和函式都會消失,無法在該 shell 中再次被使用
# execute 的方式
./myscript
# source 的方式
source myscript
. myscript # 在 bash 中將 source 視為 . 的 alias
舉例來說:
# foo.sh
NAME="Aaron"
echo $NAME
如果是使用 execute 的方式,程式執行完後,$NAME
這個變數就不存在該 shell 中:
./foo.sh
echo $NAME # 沒有東西
但如果是使用 source 的話,程式執行完後,$NAME
這個變數依然存在該 shell 中:
source foo.sh
echo $NAME # Aaron
參考資料
- Command Line Cheat Sheet @ Git Tower