我正在尋找方法來計算可能是二進制資料的尾隨換行符的數量:
- 從標準輸入讀取
- 或者已經在使用 POSIX 或 coreutils 實用程式或 Perl 的 shell 變數中(當然“二進制”至少不包括 0x0)。
這應該在沒有臨時檔案或 FIFO 的情況下作業。
當輸入在 shell 變數中時,我已經有了以下(可能很難看但)可行的解決方案:
original_string=$'abc\n\n\def\n\n\n'
string_without_trailing_newlines="$( printf '%s' "${original_string}" )"
printf '%s' $(( ${#original_string}-${#string_without_trailing_newlines} ))
3在上面的例子中給出了。
上面的想法只是減去字串長度并使用命令替換的“功能”,即丟棄任何尾隨換行符。
uj5u.com熱心網友回復:
使用 GNU sed,我們可以使用該-z選項,加上e替換命令的修飾符,并將所有這些打包在一個 sed 腳本中:
$ printf 'abc\n\n\def\n\n\n' | sed -Ezn '${s/.*[^\n]//;s/.*/wc -l <<!\n&!/ep}'
3
或者,如果字串在變數中:
$ printf '%s' "$original_string" | sed -Ezn '${s/.*[^\n]//;s/.*/wc -l <<!\n&!/ep}'
3
說明:
該
-z選項告訴 sed 輸入行以 NUL 字符而不是換行符終止。該
-n選項禁用自動列印。2 個替代命令僅適用于最后一行(
$地址),即最后一個 NUL 字符之后的所有內容,如果沒有 NUL 字符,則適用于完整的輸入字串。第一個替換命令洗掉除尾隨換行符之外的所有內容。
第二個替換命令將這些尾隨換行符替換為:
wc -l <<! !here-document 中的行數與輸入中的尾隨換行符一樣多。當使用
e修飾符時,這個新的模式空間被執行,模式空間被結果替換并列印(感謝p修飾符)。
編輯
正如 OP 所注意到的,當輸入是空字串而不是預期的0. 一個更簡單的版本,也適用于空字串可能是:
$ printf '%s' "$original_string" | sed -Ezn '${s/.*[^\n]//;p}' | wc -l
uj5u.com熱心網友回復:
一些perl基于的解決方案:
#!/usr/bin/env bash
original_string=$'abc\n\n\ndef\n\n\n'
# From a shell variable. Look ma, no pipes!
input="$original_string" perl -E '$ENV{input} =~ /(\n*)\z/; say length $1'
# From standard input (Note: The herestring adds an extra newline)
perl -0777 -nE '/(\n*)\z/; say length($1) - 1' <<<"$original_string"
# Or in a shell without herestrings (But then you're also not getting the
# above $'' quoting syntax)
printf "%s" "$original_string" | perl -0777 -nE '/(\n*)\z/; say length $1'
還有一種更詳細的方式,它不涉及將輸入作為單個塊讀取-0777(除非根本沒有換行符),這對大量資料有好處:
printf "abc\n\ndef\n\n\n" | perl -nE '
if (/^\n\z/) { # Nothing but a newline
$blank
} elsif (/\n\z/) { # Data that ends in a newline; reset counter to 1
$blank = 1
} else { # No newline (Last line is missing one?); reset counter to 0
$blank = 0
}
END { say $blank }'
uj5u.com熱心網友回復:
將 GNU awk 用于RT和不將所有輸入一次讀入記憶體:
$ printf 'abc\n\n\def\n\n\n' | awk '/./{n=NR} END{print NR-n (n && (RT==RS))}'
3
$ printf 'a\n' | awk '/./{n=NR} END{print NR-n (n && (RT==RS))}'
1
$ printf 'a' | awk '/./{n=NR} END{print NR-n (n && (RT==RS))}'
0
$ printf '' | awk '/./{n=NR} END{print NR-n (n && (RT==RS))}'
0
$ printf '\n' | awk '/./{n=NR} END{print NR-n (n && (RT==RS))}'
1
$ printf '\n\n' | awk '/./{n=NR} END{print NR-n (n && (RT==RS))}'
2
uj5u.com熱心網友回復:
另一個 perl 解決方案怎么樣:
echo -ne 'abc\n\n\def\n\n\n' | perl -0777 -ne '/\n*$/; print length($&), "\n";'
=> 3
echo -ne '\n' | perl -0777 -ne '/\n*$/; print length($&), "\n";'
=> 1
echo -ne '\n\n' | perl -0777 -ne '/\n*$/; print length($&), "\n";'
=> 2
echo -ne 'a\n\n' | perl -0777 -ne '/\n*$/; print length($&), "\n";'
=> 2
echo -ne 'a' | perl -0777 -ne '/\n*$/; print length($&), "\n";'
=> 0
- 該
-0777選項告訴 perl 一次 slurp 所有輸入行。 - 該
-ne選項類似于 sed 的選項。 - 正則運算式
\n*$匹配輸入字串的尾隨換行符。 - perl 變數
$&被分配給匹配的子字串。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/414588.html
標籤:
下一篇:我不能將歌劇與硒一起使用
