2012-03-15

Linux/UNIX 常見小問題與解決方法 (FAQ)

這篇文章用來陸續羅列一些剛好有人遇到的問題,並無意賦予其完整性。
  • Q: 開機之後,/tmp/ 資料夾裡的舊檔案都還在,而且日期都好像有點問題。不是說 /tmp/ 每次開機就會清除嗎?

    A: 先檢查一下 /tmp/ 的權限,
    $ ls -ld /tmp
    如果結果不是 "drwxrwxrwt ... root root ..." 的話,就執行以下命令:
    $ sudo chown 0.0 /tmp
    $ sudo chmod 1777 /tmp
    修改成正確的 permission。

  • Q: 我有一些檔案,其檔名的第一個字元是 "-",無法做 ls、mv、rm、vim...,只是看到 "...: invalid option -- ... Try `... --help' for more information." 要不然就是 "Unknown option argument: -...",該怎麼辦?

    A: 這是因為 ls(1)、mv(1)、rm(1) ... 這些程式會把 "-" 當做是使用者給它的選項開關(option-characters)的前導符號,所以它們會去 parse 跟隨在 "-" 這個符號之後的字元,來檢查是不是它所認識的選擇開關。例如,我們常常做的
    $ ls -l -a -t <檔名>
    這個時候,ls(1) 就會一個一個地去 parse 所有減號 "-" 後面的選項,一直到碰到一個不是以 "-" 開頭的東西,它才會假設所有的選項都已經 parsed 過了,接下來的就是其他參數(arguments)了。這些 arguments 對於 ls(1) 來說,通常是檔名或是資料夾名稱。要是檔名的前面也有一個 "-" 符號的話,它會把檔名也當做一個選擇開關,而不是 argument 來 parse。

    所以這時的處理方式是要告訴這些程式說:
    選擇開關已經都寫完了,接下來的是 argument 而不是選擇開關。
    這在作法上起碼有兩種方式。第一種就是用 "--" 來告訴它們,「選擇開關到此為止,接下來的任何東西都是 argument。」所以可以寫成
    $ ls -l -a -t -- <檔名>
    這個時候,檔名的前面就可以有 "-",而不至發生誤會。第二種方式就是在檔名的前面加上路徑(PATH)。如果檔案放在你現在的工作位置(pwd/cwd)的話,也可以寫成
    $ ls -l -a -t ./<檔名>
    如果是其他路徑,也就更不成問題,因為這些程式都足夠聰明,當碰到一些跟路徑有關係的字元時,就會離開 option-parsing 的狀態,進入到 argument-parsing 的狀態。

    其實不只是以上所列的少數程式而已,大多數 UNIX-like 系統上的程式都是這樣,它們也都用同樣的方式來規定並 parse 指令行上的 options 及 arguments。亦見:
    $ man 3 getopt
    $ man 1 getopt
    每一個指令行上,第一個就是程式本身的路徑及名稱(例如 ls 或 /bin/ls),第二個部分就是選項(options),第三個部分是 arguments。這個問題所牽涉到的就是,第二部分跟第三部分邊界的確定。

  • Q: 我用 sudo(8) 做 redirection 失敗,不能寫入 root 應該可以寫入的 directory:
    $ ls -ld /var/log/
    drwxr-xr-x 19 root root 4096 May 30 13:16 /var/log/

    $ sudo echo test > /var/log/testlog
    bash: /var/log/testlog: Permission denied
    A: 簡短的答案是,要做這事,可以用
    $ sudo sh -c "echo test > /var/log/testlog"
    或是
    $ sudo sh -c 'echo test > /var/log/testlog'
    較長的答案是,sudo(8) 跟本就「看不見」指令行上的 redirection '>',所以也沒辦法授予你所期待的權限(privilege)。redirection '>' 的權限還是決定於你現在正在使用的 shell。這個 shell 的 PID 是
    $ ps -o pid,ruser,comm | grep $$
    20200 nobody bash(樣本輸出)

沒有留言:

張貼留言