일반 텍스트 파일이 있고 각 줄은 파일의 경로입니다. 이제 grep
이 파일에서 문자열을 찾아야 합니다 .
이 파일을 "검색 소스"로 사용할 수 있는 방법이 있습니까 grep
? 아니면 bash의 모든 경로를 복사하여 붙여넣어야 합니까?
grep
둘째: 한 줄에 여러 파일을 검색 소스로 제공할 수 있는 방법이 있나요 ? 좋다
egrep --color -i "test" /tmp/1.txt, /tmp/2.txt
...?
답변1
무엇에 대해
fgrep <pattern> `cat file_list.txt`
"대신" 올바른 따옴표를 추가하십시오. - 당신이 원하는 것을 이해한다면
답변2
답변이 다소 모호한 몇 가지 질문을 제기하기 때문에 이 답변을 다시 작성했습니다. 이 답변을 통해 안개가 조금이나마 해소되길 바랍니다.
참고: xargs
인수가 너무 많아 명령줄에서 사용할 수 있는 메모리를 초과하는 경우 위치 인수(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
명령줄로 바꿉니다. 파일 이름에 공백이나 쉘 와일드카드 문자( )가 포함되어 있으면 \[?*
실패합니다 . 목록이 너무 커서 명령줄 길이 제한(많은 시스템에서 약 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*