在 Shell 裡面直接執行 Python 跟 PHP 指令

bash 可以直接在提示符號後面輸入複雜的指令工作,很多時候很方便做一些日常工作。

# 印出每個 csv 檔案的頭四行
$ for file in *.csv; do echo === $file ===; head -4 $file; done

AWK 在使用時也可以直接在指令列輸入內容。

# 輸出第三欄跟第四欄的總和
$ cat large.csv | awk '{male += $3; female+=$4} END{print male, female}'

PHPPython 其實也提供了類似的用法。輸入指令的時候 ; 之類的字元不能省略,如同正常寫 script 一樣,語法必須正確。

# 把檔案每一行都 urlencode 然後印到畫面上
$ cat large2.txt | php -r 'while($line = fgets(STDIN)){ echo urlencode($line),"\n"; }'
# 單純印出每一行,當然可以塞入更多邏輯
$ cat large2.txt | python3 -c '
> import sys
> for line in sys.stdin: print(line)
> '

注意 Python 雖然可以寫成單行流,但實用上沒那麼方便。

# 這樣可以
$ python3 -c 'for i in range(5): print(i**2 if i % 2 == 0 else i)'
0
1
4
3
16
# 這樣也可以
$ python3 -c 'import json; print(json.dumps({"a":1}))'
{"a": 1}
# 這樣不行
$ python3 -c 'import json; for i in range(5): print(json.dumps({"a":i}))'
  File "<string>", line 1
    import json; for i in range(5): print(json.dumps({"a":i}))
                 ^
SyntaxError: invalid syntax

當然也可以用這種方法把 Python 或 PHP 安插在 bash script 裡面。可讀性就要想一下怎麼控制,寫太長的話會不容易閱讀與維護。

#!/bin/bash

# 把 csv 檔案轉換成多個 PHP 陣列並分開存檔
# 沒有特別意義就是個示範

data_file=$1

zcat "$data_file" \
 | grep -v 'LINE_TO_REMOVE' \
 | php -r '
while ($line = fgets(STDIN)) {
    $line = trim($line);
    $fields = explode(",", $line);
    $id = $fields[0];
    $file = sprintf("%s/data_%d.php", __DIR__, $id);
    $content = "<?php return " . var_export($fields, true) . ";";
    file_put_contents($file, $content);
}'