我有一个纯文本文件,每一行都是文件的路径。现在我必须grep
在这些文件中查找字符串。
有什么方法可以使用此文件作为“搜索源”吗grep
?或者我是否必须复制并粘贴 bash 的每个路径?
第二:有没有办法grep
在一行中提供不同的文件作为搜索源?喜欢
egrep --color -i "test" /tmp/1.txt, /tmp/2.txt
...?
答案1
关于什么
fgrep <pattern> `cat file_list.txt`
注意添加正确的引号“而不是”——如果我明白你想要做什么
答案2
我重写了这个答案,因为它提出了一些问题,而这些问题的答案有点模糊。我希望这个答案能驱散一些迷雾......
注意:xargs
当参数太多以至于超出命令行可用的内存时,Using 适合将位置参数(args)传递给程序...
注释在脚本中。
#!/bin/bash
rm -f "/tmp/file "*
# Create some dummy test files and write their names to /tmp/list
for x in {A..D} ;do
echo "text-$x" >"/tmp/file $x"
echo "/tmp/file $x"
done >"/tmp/list"
# Set up Quirk 1... with an escaped char \A in the file-name.
# Replace one of the file-names in the list with a quirky but valid one.
echo 'quirk 1. \A in filename' >'/tmp/file \A'
sed -i 's/A/\\A/' "/tmp/list"
# The next two lines show that
# 'file \A' is in the list and DOES exist.
# 'file A' is NOT in the list, but DOES exist.
# Therefore, 'file A' should NOT produce a 'grep' match
echo "Quirk 1. backslash in file-name"
echo " ls:"; ls -1 '/tmp/file '*A |nl
echo " list:"; sed -n '/A/p' "/tmp/list" |nl
echo "===================="
# Set up Quirk 2... with $D in the file name
# Replace one of the file-names in the list with a quirky but valid one.
echo 'quirk 2. $D in filename' >'/tmp/file $D'
sed -i 's/D/\$D/' "/tmp/list"
D='D'
# The next two lines show that
# 'file $D' is in the list and DOES exist.
# 'file D' is NOT in the list, but DOES exist.
echo "Quirk 2. var \$D=$D in file-name"
echo " ls:"; ls -1 '/tmp/file '*D |nl
echo " list:"; sed -n '/D/p' "/tmp/list" |nl
echo "===================="
# The regex search pattern
regex='(A|C|D)'
# Read lines of a file, and use them as positional parameters.
# Note: 'protection' means protected from bash pre-processing. (eg path expansion)
# ============================================================
###
echo
echo "========================================"
echo "Passing parameters to 'grep' via 'xargs'"
echo "========================================"
echo
###
echo "# Use 'xargs' with the assumption that every file name contains no meta characters."
echo "# The result is that file names which contain meta characters, FAILS."
echo "# So it interprets '\A' as 'A' and whitespace as a delimiter!"
<"/tmp/list" xargs grep -E -H "$regex"
echo =====; echo "ERROR: All files in the sample list FAIL!"
echo =====; echo
###
echo "# Use xargs -I{} to avoid problems of whitespace in filenames"
echo "# But the args are further interpreted by bash, as in escape '\' expansion."
echo "# Bash still interprets xarg's '\A' as 'A' and so 'grep' processes the wrong file"
echo "# However the -I{} does protect the $D from var expansion"
<"/tmp/list" xargs -I{} grep -E -H "$regex" {}
echo =====; echo "ERROR: The 1st line refers to 'file A' which is NOT in the list!"
echo =====; echo
###
echo "# Use xargs -0 to avoid problems of whitespace in filenames"
echo "# 'xargs -0' goes further with parameter protection than -I."
echo "# Quotes and backslash are not special (every character is taken literally)"
<"/tmp/list" tr '\n' '\0' |xargs -0 grep -E -H "$regex"
echo ==; echo "OK"
echo ==; echo
###
echo "====================================="
echo "Passing parameters directly to 'grep'"
echo "====================================="
echo
###
echo "# Use 'grep' with the assumption that every file name contains no meta characters."
echo "# The result is that file names which contain meta characters, FAILS."
grep -E -H "$regex" $(cat "/tmp/list")
echo =====; echo "ERROR: All files in the sample list FAIL!"
echo =====; echo
###
echo '# Set bash positional parameters "$1" "$2" ... "$n"'
echo "# Note: destructive... original parameters are overwritten"
echo '# and, you may need to reset $IFS to its original value'
IFS=$'\n'
set $(cat "/tmp/list")
grep -E "$regex" "$@"
echo ==; echo "OK"
echo ==; echo
###
echo '# Set bash positional parameters "$1" "$2" ... "$n"'
echo '# Note: non-destructive... original parameters are not overwritten'
echo '# Variable set in the sub-shell are NOT accessible on return.'
echo '# There is no need to reset $IFS'
( IFS=$'\n'
set $(cat "/tmp/list")
grep -E "$regex" "$@" )
echo ==; echo "OK"
echo ==; echo
###
echo '# Using bash array elements "${list[0]}" "${list[1]}" ... "${list[n-1]}"'
echo '# Note: you may need to reset $IFS to its original value'
IFS=$'\n'
list=($(cat "/tmp/list"))
grep -E "$regex" "${list[@]}"
echo ==; echo "OK"
echo ==; echo
###
这是输出
Quirk 1. backslash in file-name
ls:
1 /tmp/file A
2 /tmp/file \A
list:
1 /tmp/file \A
====================
Quirk 2. var $D=D in file-name
ls:
1 /tmp/file D
2 /tmp/file $D
list:
1 /tmp/file $D
====================
========================================
Passing parameters to 'grep' via 'xargs'
========================================
# Use 'xargs' with the assumption that every file name contains no meta characters.
# The result is that file names which contain meta characters, FAILS.
# So it interprets '\A' as 'A' and whitespace as a delimiter!
grep: /tmp/file: No such file or directory
grep: A: No such file or directory
grep: /tmp/file: No such file or directory
grep: B: No such file or directory
grep: /tmp/file: No such file or directory
grep: C: No such file or directory
grep: /tmp/file: No such file or directory
grep: $D: No such file or directory
=====
ERROR: All files in the sample list FAIL!
=====
# Use xargs -I{} to avoid problems of whitespace in filenames
# But the args are further interpreted by bash, as in escape '\' expansion.
# Bash still interprets xarg's '\A' as 'A' and so 'grep' processes the wrong file
# However the -I{} does protect the D from var expansion
/tmp/file A:text-A
/tmp/file C:text-C
/tmp/file $D:quirk 2. $D in filename
=====
ERROR: The 1st line refers to 'file A' which is NOT in the list!
=====
# Use xargs -0 to avoid problems of whitespace in filenames
# 'xargs -0' goes further with parameter protection than -I.
# Quotes and backslash are not special (every character is taken literally)
/tmp/file \A:quirk 1. \A in filename
/tmp/file C:text-C
/tmp/file $D:quirk 2. $D in filename
==
OK
==
=====================================
Passing parameters directly to 'grep'
=====================================
# Use 'grep' with the assumption that every file name contains no meta characters.
# The result is that file names which contain meta characters, FAILS.
grep: /tmp/file: No such file or directory
grep: \A: No such file or directory
grep: /tmp/file: No such file or directory
grep: B: No such file or directory
grep: /tmp/file: No such file or directory
grep: C: No such file or directory
grep: /tmp/file: No such file or directory
grep: $D: No such file or directory
=====
ERROR: All files in the sample list FAIL!
=====
# Set bash positional parameters "$1" "$2" ... "$n"
# Note: destructive... original parameters are overwritten
# and, you may need to reset $IFS to its original value
/tmp/file \A:quirk 1. \A in filename
/tmp/file C:text-C
/tmp/file $D:quirk 2. $D in filename
==
OK
==
# Set bash positional parameters "$1" "$2" ... "$n"
# Note: non-destructive... original parameters are not overwritten
# Variable set in the sub-shell are NOT accessible on return.
# There is no need to reset $IFS
/tmp/file \A:quirk 1. \A in filename
/tmp/file C:text-C
/tmp/file $D:quirk 2. $D in filename
==
OK
==
# Using bash array elements "${list[0]}" "${list[1]}" ... "${list[n-1]}"
# Note: you may need to reset $IFS to its original value
/tmp/file \A:quirk 1. \A in filename
/tmp/file C:text-C
/tmp/file $D:quirk 2. $D in filename
==
OK
==
答案3
如果您想一次搜索多个文件,可以在命令行末尾键入所有文件,并用空格分隔。
grep -i test /path/to/file /some/other/file
您可以使用通配符模式。
grep -i test README ChangeLog *.txt
如果您有一个文件列表,每行一个文件名,那么您有多种可能性。如果您的文件名中没有任何外来字符,则以下任一方法都可以:
grep -i test -- $(cat list_of_file_names.txt)
<list_of_file_names.txt xargs grep -i test -H --
第一个命令将命令的输出替换cat list_of_file_names.txt
到命令行中。如果任何文件名包含空格或 shell 通配符 ( \[?*
),则会失败。如果列表太大以至于超出了命令行长度限制(在许多系统上超过约 128kB),它也会失败。如果任何文件名包含空格,第二个命令将失败\"'
。egrep
如果命令行长度限制需要,它会负责运行多次。该-H
选项确保grep
始终打印匹配文件的名称,即使它碰巧是用单个文件调用的。确保--
如果第一个文件名以 开头-
,它将被视为文件名而不是选项。
处理可能包含除换行符之外的任何字符的文件名的安全方法是关闭除换行符之外的空格上的拆分并关闭通配符(通配符扩展)。
set -f; IFS='
'
grep -i test -- $(cat list_of_file_names.txt)
set +f; unset IFS
答案4
cat filenames.txt | xargs grep <pattern>
grep <pattern> filename1 filename2 filename*