2010-08-25 38 views
3

我有使用/dev/urandomtr產生長的,隨機串的ksh腳本:一致的執行tr?

STRING="$(cat /dev/urandom|tr -dc 'a-zA-Z0-9-_'|fold -w 64 |head -1)"

在哪裏使用此它導致了大寫和小寫字母字符的64個字符的Linux和AIX服務器,數字,短劃線和下劃線字符。例如:

W-uch3_4fbnk34u2nc08w_nj23n089023ncNjxz979823n23-n88h30pmLCxkMKj

當我使用的腳本在Solaris範圍被解釋爲文字,它導致從該組aAzZ09-_字符串。例如:

AA0z9_aZ-a-z00aZ9_azAZa0zZza9-Az0-_za-9aa0az_a0z-0a0z000-A9Z_0a

奇怪的是,本Solaris服務器上tr手冊頁表示中使用的語法應該產生所期望的結果。

想法是使用/dev/urandom來產生一個僞隨機字符串,我們從中提取字符,以便結果a)不包含空格和b)不包含s​​hell特殊字符。該字符串將在命令行中用作稍後腳本中的參數。我們不想使用像:alnum:這樣的類,因爲locale可以將它們轉換爲在命令行上不起作用的多字節值。這個ksh單線程在完成很多安裝之前完成了這個技巧,直到我們到達Solaris。

我們暫時將其轉換爲一個有點討厭的Perl正則表達式。是否有tr或某些其他實用程序或內置ksh的語法,它們將在UNIX變體中一致地執行此任務,並且通用安裝?不一定是單線,但簡單感謝。

更新:我們嘗試了沒有運氣的語言環境設置。等待使用xpg6版本的結果。

$ uname -a 
SunOS hostname 5.10 Generic_142900-04 sun4u sparc SUNW,SPARC-Enterprise 
$ cat /dev/urandom | tr -dc "a-zA-Z0-9-_" | fold -w 64 | head -1 | sed 's/^-/_/' 
0-a9-z9a_zzZAa_a_0az-9_z0a_90Z_9az09aZzZAa-9aa_-__za0ZA9_ZzzZazA 
$ set | grep '^L[AC]' 
LANG=C 
LC_ALL=C 
LC_COLLATE=en_US 
LC_CTYPE=en_US 
LC_MESSAGES=en_US 
LC_MONETARY=en_US 
LC_NUMERIC=en_US 
LC_TIME=en_US 
$ export LC_CTYPE="$LC_ALL" LC_MESSAGES="$LC_ALL" 
$ set | grep '^L[AC]' 
LANG=C 
LC_ALL=C 
LC_COLLATE=en_US 
LC_CTYPE=C 
LC_MESSAGES=C 
LC_MONETARY=en_US 
LC_NUMERIC=en_US 
LC_TIME=en_US 
$ cat /dev/urandom | tr -dc "a-zA-Z0-9-_" | fold -w 64 | head -1 | sed 's/^-/_/' 
0900z9az99_a0za09__0zA0_Z--Z_-Aa-AaA9zAZz-Aa90A00z__ZzA9A-Z0aA_- 
$ unset LC_ALL; export LC_COLLATE=C LC_NUMERIC=C LC_TIME=C 
$ set | grep '^L[AC]' 
LANG=C 
LC_COLLATE=C 
LC_CTYPE=C 
LC_MESSAGES=C 
LC_MONETARY=en_US 
LC_NUMERIC=C 
LC_TIME=C 
$ cat /dev/urandom | tr -dc "a-zA-Z0-9-_" | fold -w 64 | head -1 | sed 's/^-/_/' 
_AA9aA_Za-A0-AZa_A-0ZA--a_za-a9zZZz__a0az_-0A-9-0aA-0za00A-__9-0 
$ unset LANG LC_COLLATE LC_NUMERIC LC_TIME 
$ set | grep '^L[AC]' 
LC_CTYPE=C 
LC_MESSAGES=C 
LC_MONETARY=en_US 
$ cat /dev/urandom | tr -dc "a-zA-Z0-9-_" | fold -w 64 | head -1 | sed 's/^-/_/' 
_-_9zz9Z-Z-Z-Z_0_a9zzzZZaAa--9_zAZaaAZz-ZaAZ09Z-_z-zz09ZZAzAz0Z0 
$ unset LC_CTYPE LC_MESSAGES LC_MONETARY 
$ set | grep '^L[AC]' 
$ cat /dev/urandom | tr -dc "a-zA-Z0-9-_" | fold -w 64 | head -1 | sed 's/^-/_/' 
_0aAa9_Z_a_Z--_Az-aa0ZA0ZzZ-9Aa9-Z0--0A_Z0Zaz-AA_Zz0z---Z_99z_a9 
$ export LANG=C LC_ALL=C LC_COLLATE=C LC_CTYPE=C LC_MESSAGES=C LC_MONETARY=C LC_NUMERIC=C LC_TIME=C 
$ set | grep '^L[AC]' 
LANG=C 
LC_ALL=C 
LC_COLLATE=C 
LC_CTYPE=C 
LC_MESSAGES=C 
LC_MONETARY=C 
LC_NUMERIC=C 
LC_TIME=C 
$ cat /dev/urandom | tr -dc "a-zA-Z0-9-_" | fold -w 64 | head -1 | sed 's/^-/_/' 
Za_000z9aa--aA00zAAZza0AA90090--z0a00_zZ9ZA0_---aZZ09a0ZA0_0zZaa 
$ cat /dev/urandom | tr -dc "[a-z][A-Z][0-9]-_" | fold -w 64 | head -1 | sed 's/^-/_/' 
x7dni9gIXVF6AHQc3B-H6hjnBVHChJ9zM-z5EQ5UEruATI_NNFaCoVLOqM6gVaT5 
$ 

當然,在最後一個版本的Linux中會出現方括號。

回答

2

如果您將路徑設置爲/ usr/xpg6/bin /,那麼它將按預期工作 語言環境在此似乎沒有任何影響。跨平臺破解是:

tr -dc '[a-z][A-Z][0-9]_-' < /dev/urandom | tr -d '][' | fold -w64 | head -n1 
+0

我們擁有相同的體驗 - 所有的語言環境設置都沒有任何影響。但是今天早上我聽到了關於測試的消息,並且tr的xpg6版本完美地工作了。我們現在修訂的腳本版本可以在Solaris,AIX和我可以訪問的所有Linux版本上運行。 – 2010-08-27 11:05:36

0

嘗試:

LANG=C tr -dc 'a-zA-Z0-9-_' 

也嘗試指定的完整路徑tr(從/usr/bin/tr比較結果對XPG版本)。

Solaris上的-c(「values」)和-C(「characters」)之間的區別是什麼?在Linux上它們是一樣的。

另外:你能用head -c 64代替fold -w 64 |head -1嗎?此外,您還可以消除cattr ... < /dev/urandom | ...

最終,視情況而定的其中一個可以爲你工作(但字符集可能比你想要的東西有點不同):

base64 /dev/urandom | head -c 64 

uuencode /dev/urandom | head -c 64 
+0

謝謝,我會給這些鏡頭,讓你知道。我的客戶是UTC + 1,所以我必須等到明天再測試。 – 2010-08-25 16:56:09

+0

'LANG = C'可能會也可能不會工作,這取決於如何設置LC_COLLATE類別(請參見[我的答案](http://stackoverflow.com/questions/3567882/consistent-implementation-of-tr/3569199 #3569199))。 – Gilles 2010-08-25 18:49:29

+0

我受到Locale響應的鼓舞,但是當我們在Solaris主機上測試時,它對tr的行爲沒有任何影響。謝謝,不過。 – 2010-08-27 11:10:18

2

您觀察到的操作系統之間沒有區別,但具有不同語言環境設置的不同計算機不同。您的Solaris計算機將LC_COLLATE設置爲非默認值,這對於您遇到的那些問題確實是一個好方法。

  • 如果環境變量LC_ALL被設置,它的值被用於所有三類:

    Locale的設置從環境設定如下。

  • 否則,如果LC_FOO已設置,則其值將用於類別LC_FOO

  • 否則,如果設置了LANG,則其值將用於未明確設置的類別。

  • 默認語言環境被稱爲C。在Unix系統上,POSIXC的同義詞。

主要語言環境類別是:

  • LC_CTYPE指示用於文件名,文件內容和終端I/O字符集和編碼。除非您知道這是不準確的(例如,因爲特定的文件格式指定了特定的編碼),您應該謹慎地保留此設置。

  • LC_MESSAGES是用戶看到的消息的語言。你應該保留這個設置。如果您確實需要解析錯誤消息,請設置LC_MESSAGES=C

  • LC_COLLATE指示字符的排序順序。在腳本中幾乎總是不受歡迎的。除C以外的大多數值會造成麻煩,如A - Z與小寫字母匹配。

  • 偶爾LC_NUMERIC可能會引起麻煩,因爲數字可能會打印不同的標點符號,而LC_TIME會影響某些命令顯示日期和時間的方式。其他類別在腳本中幾乎不存在。

下面是腳本合理的策略(警告,直接輸入到瀏覽器):

unset LANGUAGE # a GNU-specific setting 
if [ -n "$LC_ALL" ]; then 
    export LC_CTYPE="$LC_ALL" LC_MESSAGES="$LC_ALL" 
    unset LC_ALL 
elif [ -n "$LANG" ]; then 
    export LC_COLLATE=C LC_NUMERIC=C LC_TIME=C 
else 
    unset LC_COLLATE LC_NUMERIC LC_TIME 
fi 

標準shell實用程序服從區域設置。除非你告訴Perl,否則Perl不會。

+0

謝謝,這看起來很有希望。我發郵件給我的客戶,並要求他們在早上進行測試。 – 2010-08-25 21:55:22

+0

+1的詳細答案,使我更深入地調查Locale。不幸的是,從問題更新中可以看到,我們對Locale設置做的任何操作都沒有導致正確的行爲。 – 2010-08-27 11:09:10

相關問題