替换tr'\ n''\ 0'的绝佳方法(空字节在运行时生成警告)

时间:2018-12-29 05:54:04

标签: bash

我强烈怀疑我的代码中grep的最佳用法,并希望找到一种更好,更简洁的编码样式,以便从cookie文件中提取会话ID和安全级别:

cat mycookie 
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_127.0.0.1 FALSE   /   FALSE   0   PHPSESSID   1hjs18icittvqvpa4tm2lv9b12
#HttpOnly_127.0.0.1 FALSE   /mydir/ FALSE   0   security    medium

预期的输出是SSID哈希值:

1hjs18icittvqvpa4tm2lv9b12

在命令行中用greptr '\n' '\0'就像一个超级按钮一样,但是在执行bash代码时会生成警告(warning: command substitution: ignored null byte in input”)。以下是相关代码(带有警告):

ssid=$(grep -Po 'PHPSESSID.*' path/sessionFile | grep -Po '[a-z]|[0-9]' | tr '\n' '\0')

我正在使用bash 4.4.12 (x86_64-pc-linux-gnu),可以读到here这个清晰的解释:

  

Bash变量存储为C字符串。 C字符串以NUL终止。   因此,它们无法按照定义存储NUL。

在两种情况下,我都可以看到herethere是使用read的编码解决方案:

# read content from stdin into array variable and a scalar variable "suffix"
array=( )
while IFS= read -r -d '' line; do
  array+=( "$line" )
done < <(process that generates NUL stream here)
suffix=$line # content after last NUL, if any

# emit recorded content
printf '%s\0' "${array[@]}"; printf '%s' "$suffix"

在这种情况下,我不想使用数组或while循环。我使用sed找到了解决方法:

ssid=$(grep -Po 'PHPSESSID.*' path/sessionFile | grep -Po '[a-z]|[0-9]' | tr '\n' '_' | sed -e 's/_//g')

我的两个问题是:

1)是否可以在不使用tr '\n' '\0'read循环中替代while的更好方法?
2)正确提取SSID和安全级别是更好的方法吗?

Thx

2 个答案:

答案 0 :(得分:2)

您似乎正在尝试摆脱grep的输出中的换行符,但是将它们转换为null并不会这样做。空值在您的终端中不可见,但仍然存在,并且(像许多其他非打印字符一样)如果将其视为您的实际数据的一部分,将会造成严重破坏。如果您想摆脱换行符,只需告诉tr... | tr -d '\n'为您删除它们。但是,如果您尝试从Netscape格式的cookie文件中获取PHPSESSID值,则有更好的方法:

ssid=$(awk '($6 == "PHPSESSID") {print $7}' path/sessionFile)

这会在第六个字段中查找“ PHPSESSID”(仅 )(而不是在路径或cookie值中-都可以合法显示的两个位置),并专门打印匹配行的第七个字段(不仅是“ PHPSESSID”之后的任何数字或小写字母。

答案 1 :(得分:1)

如果您不想使用awk,也可以尝试以下方法:

ssid=$(grep -P '\bPHPSESSID\b' you_cookies_file)
echo $ssid   # for debug only

输出类似

的内容
#HttpOnly_127.0.0.1 FALSE / FALSE 0 PHPSESSID 1hjs18icittvqvpa4tm2lv9b12

然后使用cut(1)提取相关字段:

echo $ssid |cut -d" " -f7

输出

1hjs18icittvqvpa4tm2lv9b12

当然您应该捕获最后一个echo

更新

如果您不想使用cut,可以使用以下命令进行模拟:

echo $ssid | (read a1 b2 c3 d4 e5 f6 g7; echo $g7)

演示捕获变量:

$ field=$(echo $ssid | (read a1 b2 c3 d4 e5 f6 g7; echo $g7))
$ echo $field
1hjs18icittvqvpa4tm2lv9b12
$

另一种方法是使用位置参数,将字符串传递给一个函数,该函数随后引用$ 7。也许更干净。否则,您可以使用数组:

array=($(echo $ssid))
echo ${array[6]}   # outputs the 7th field

也应该可以使用正则表达式和/或bash操作字符串,但对我来说似乎有点困难。