awk 在*系统调用*中处理带有特殊字符的文件名
awk processing filenames with special characters in *system call*
我正在处理大量 md5, dir/filename
对。我需要将文件大小插入到列表中以制作 md5, size, dir/filename
三元组列表。
数据文件的相关片段是:
file MD5sum-stage1A.txt
...
d9c6be18d35619c7532f9c94f5a9bf58 /mnt/dir1/dir2/branch1/04 05 Custom .mp4
01c0fadb91c8ef0815a7753ad25a8c1c /mnt/dir1/dir2/branch1/branch2/Using the -proc directory and the $$ Variable.odt
...
EOF
第二条数据线有问题,文件名中有$$
。
除了一个例外,代码可以正常工作。
以下是到目前为止的代码:
someone@system01:~/tmp$ awk 'NR==15522, NR==15523 {
> md5=
> file=substr([=11=],35)
> size="###"
> cmd=sprintf("stat --format=%s \"%s\"", "%s",file)
> cmd | getline size
> close(cmd)
> printf "%s\t%s\t%s\n",md5, size, file
> }' MD5sum-stage1A.txt
d9c6be18d35619c7532f9c94f5a9bf58 6747587 /mnt/dir1/dir2/dir3/04 05 Custom .mp4
stat: cannot stat '/mnt/dir1/dir2/Using the -proc directory and the 20483 Variable.odt': No such file or directory
01c0fadb91c8ef0815a7753ad25a8c1c ### /mnt/dir1/dir2/Using the -proc directory and the $$ Variable.odt
到目前为止,代码正在处理 shell 的细微差别,并处理文件名中的空格和大多数字符。
但是,shell 似乎想要用 processid 替换“$$”。
使用 Awk 如何减轻这种行为?
MD5和文件大小一起生成更容易
例如使用 find
定位文件并使用 awk
格式化输出:
find /mypath -type f -exec md5sum {} \; -exec stat -c %s {} \; | \
awk 'NF==1{print hash,,rest;next}{hash=;rest=substr([=10=],35)}'
如果不能生成MD5,需要重新使用文件,可以避免awk
,用bash read
命令:
while read hash f; do
echo "$hash $(stat -c %s "$f") $f"
done < file
我会这样做:使用 xargs 一次读取一行,然后使用 cut -d" "
分割该行以剪切输入的部分:
xargs -n1 -d $'\n' bash -c 'f=$(cut -d" " -f3- <<<""); printf "%s\t%s\t%s\n" "$(cut -d" " -f1 <<<"")" "$(stat -c %s "$f")" "$f"' --
或者用双空格和换行符替换一些您可以轻松处理的不可读字符(如 0x01 字节):
sed 's/ /\x01/' | tr '\n' '' |
xargs -n2 -d $'\x01' bash -c 'printf "%s\t%s\t%s\n" "" "$(stat -c %s "")" ""' --
甚至用双空格代替一些不可读的字符:
sed 's/ /\x01/' |
while IFS=$'\x01' read -r md5 file; do
printf "%s\t%s\t%s\t\n" "$md5" "$(stat -c %s "$file")" "$file"
done
问题是您从 awk 调用 stat 时使用的引号与从 shell 调用 stat 时使用的引号不同——如果您从 shell 调用 stat 时使用与您相同的引号在 awk 命令中使用你会得到同样的错误。看:
$ ls
'foo $$ bar'
$ stat --format=%s "foo $$ bar"
stat: cannot stat 'foo 1913 bar': No such file or directory
现在有了正确的引用:
$ stat --format='%s' 'foo $$ bar'
6
在您的 awk 命令中,您当前使用的引号不正确:
awk -v file='foo $$ bar' 'BEGIN{cmd=sprintf("stat --format=%s \"%s\"", "%s",file); cmd | getline size; close(cmd); print file, size}'
stat: cannot stat 'foo 2523 bar': No such file or directory
foo $$ bar
但如果您使用与正确引用的 shell 命令中相同的引号:
awk -v file='foo $$ bar' 'BEGIN{cmd=sprintf("stat --format=7%s7 7%s7", "%s",file); cmd | getline size; close(cmd); print file, size}'
foo $$ bar 6
您可以在格式字符串中打印文字 %
,只需将其加倍顺便说一下:
awk -v file='foo $$ bar' 'BEGIN{cmd=sprintf("stat --format=7%%s7 7%s7",file); cmd | getline size; close(cmd); print file, size}'
foo $$ bar 6
下面是我真正处理这个问题的方法:
$ ls -1
'an other file'
files
'foo $$ bar'
$ cat files
12345 an other file
987 foo $$ bar
$ cut -f2- files | xargs -d'\n' stat --format='%s'
5
6
$ cut -f2- files | xargs -d'\n' stat --format='%s' |
awk -v OFS='\t' 'NR==FNR{size[NR]=[=15=]; next} {print size[FNR], [=15=]}' - files
5 12345 an other file
6 987 foo $$ bar
非常感谢您的回答,他们给了我一些想法并希望简化和优化初始任务。因此,本着分享我最终得到的东西的精神,也许它会对其他人有用,是:
find /media/BACKUPS/foo -not -path '*/\.*' -type f -exec md5sum {} \; -printf '%s\n' | awk 'NF==1{printf "%s\t%s\t%s\n",hash,,rest;next}{hash=;rest=substr([=10=],index([=10=],))}' > MD5sum-dataset-foo.txt
再一次,非常感谢...
我正在处理大量 md5, dir/filename
对。我需要将文件大小插入到列表中以制作 md5, size, dir/filename
三元组列表。
数据文件的相关片段是:
file MD5sum-stage1A.txt
...
d9c6be18d35619c7532f9c94f5a9bf58 /mnt/dir1/dir2/branch1/04 05 Custom .mp4
01c0fadb91c8ef0815a7753ad25a8c1c /mnt/dir1/dir2/branch1/branch2/Using the -proc directory and the $$ Variable.odt
...
EOF
第二条数据线有问题,文件名中有$$
。
除了一个例外,代码可以正常工作。 以下是到目前为止的代码:
someone@system01:~/tmp$ awk 'NR==15522, NR==15523 {
> md5=
> file=substr([=11=],35)
> size="###"
> cmd=sprintf("stat --format=%s \"%s\"", "%s",file)
> cmd | getline size
> close(cmd)
> printf "%s\t%s\t%s\n",md5, size, file
> }' MD5sum-stage1A.txt
d9c6be18d35619c7532f9c94f5a9bf58 6747587 /mnt/dir1/dir2/dir3/04 05 Custom .mp4
stat: cannot stat '/mnt/dir1/dir2/Using the -proc directory and the 20483 Variable.odt': No such file or directory
01c0fadb91c8ef0815a7753ad25a8c1c ### /mnt/dir1/dir2/Using the -proc directory and the $$ Variable.odt
到目前为止,代码正在处理 shell 的细微差别,并处理文件名中的空格和大多数字符。 但是,shell 似乎想要用 processid 替换“$$”。
使用 Awk 如何减轻这种行为?
MD5和文件大小一起生成更容易
例如使用 find
定位文件并使用 awk
格式化输出:
find /mypath -type f -exec md5sum {} \; -exec stat -c %s {} \; | \
awk 'NF==1{print hash,,rest;next}{hash=;rest=substr([=10=],35)}'
如果不能生成MD5,需要重新使用文件,可以避免awk
,用bash read
命令:
while read hash f; do
echo "$hash $(stat -c %s "$f") $f"
done < file
我会这样做:使用 xargs 一次读取一行,然后使用 cut -d" "
分割该行以剪切输入的部分:
xargs -n1 -d $'\n' bash -c 'f=$(cut -d" " -f3- <<<""); printf "%s\t%s\t%s\n" "$(cut -d" " -f1 <<<"")" "$(stat -c %s "$f")" "$f"' --
或者用双空格和换行符替换一些您可以轻松处理的不可读字符(如 0x01 字节):
sed 's/ /\x01/' | tr '\n' '' |
xargs -n2 -d $'\x01' bash -c 'printf "%s\t%s\t%s\n" "" "$(stat -c %s "")" ""' --
甚至用双空格代替一些不可读的字符:
sed 's/ /\x01/' |
while IFS=$'\x01' read -r md5 file; do
printf "%s\t%s\t%s\t\n" "$md5" "$(stat -c %s "$file")" "$file"
done
问题是您从 awk 调用 stat 时使用的引号与从 shell 调用 stat 时使用的引号不同——如果您从 shell 调用 stat 时使用与您相同的引号在 awk 命令中使用你会得到同样的错误。看:
$ ls
'foo $$ bar'
$ stat --format=%s "foo $$ bar"
stat: cannot stat 'foo 1913 bar': No such file or directory
现在有了正确的引用:
$ stat --format='%s' 'foo $$ bar'
6
在您的 awk 命令中,您当前使用的引号不正确:
awk -v file='foo $$ bar' 'BEGIN{cmd=sprintf("stat --format=%s \"%s\"", "%s",file); cmd | getline size; close(cmd); print file, size}'
stat: cannot stat 'foo 2523 bar': No such file or directory
foo $$ bar
但如果您使用与正确引用的 shell 命令中相同的引号:
awk -v file='foo $$ bar' 'BEGIN{cmd=sprintf("stat --format=7%s7 7%s7", "%s",file); cmd | getline size; close(cmd); print file, size}'
foo $$ bar 6
您可以在格式字符串中打印文字 %
,只需将其加倍顺便说一下:
awk -v file='foo $$ bar' 'BEGIN{cmd=sprintf("stat --format=7%%s7 7%s7",file); cmd | getline size; close(cmd); print file, size}'
foo $$ bar 6
下面是我真正处理这个问题的方法:
$ ls -1
'an other file'
files
'foo $$ bar'
$ cat files
12345 an other file
987 foo $$ bar
$ cut -f2- files | xargs -d'\n' stat --format='%s'
5
6
$ cut -f2- files | xargs -d'\n' stat --format='%s' |
awk -v OFS='\t' 'NR==FNR{size[NR]=[=15=]; next} {print size[FNR], [=15=]}' - files
5 12345 an other file
6 987 foo $$ bar
非常感谢您的回答,他们给了我一些想法并希望简化和优化初始任务。因此,本着分享我最终得到的东西的精神,也许它会对其他人有用,是:
find /media/BACKUPS/foo -not -path '*/\.*' -type f -exec md5sum {} \; -printf '%s\n' | awk 'NF==1{printf "%s\t%s\t%s\n",hash,,rest;next}{hash=;rest=substr([=10=],index([=10=],))}' > MD5sum-dataset-foo.txt
再一次,非常感谢...