cmdlet은 제가 PS에서 많이 사용하는 것인데 매우 편리합니다.
이름이 "test"로 시작하는 모든 파일을 얻으려면 다음을 수행합니다.
ls | ?{$_.name -like 'test*'}
nix 관리자가 bash에서 이 작업을 수행할 수 있는 깔끔한 방법은 무엇입니까? Bash는 분명히 객체 기반이 아닌 텍스트이므로 명령은 다음과 같습니다.
ls | ?{<column#> -like 'test*'}
나는 ls 명령( ls test*
작동하지만 명령에 따라 다름)에 대해 묻는 것이 아니며, 이와 같은 필터를 통해 출력을 파이프하는 방법에 해당하는 간결한 bash를 찾고 있습니다.
답변1
긴 이야기 짧게: 그게 마음에 안 든다면 ls
, 그래도 그렇지요.아니요아래 설명된 명령과 관련하여 를 사용합니다 arr=(); for foo in * [!*]*; do [[ $foo == test* ]] && arr+=("$foo"); done
. 이는 기본적으로 arr=list_files.filter((i) -> (i.glob_match('test*'));
다른 언어로 작성하는 것입니다.
그러나 계속해서 읽으면 이것이 ls
괜찮고 이러한 테스트를 직접 배열 할당으로 건너뛰어야 한다는 것을 알게 될 것입니다 arr=(test*)
(mikeserv는 제가 이 말을 먼저 해야 한다는 것을 깨닫게 해주었습니다).
텍스트 필터링에 대한 빠른 검토
다른 사람들이 의견에서 언급했듯이 Unix 쉘은 객체 패키지가 아닌 텍스트 스트림을 파이프합니다. Unix 세계에서는 Windows보다 파일 이름과 기타 많은 공백에 더 많은 내용을 허용하므로 쉘 워드 경계만 안전합니다. 다행히 허용되지 않는 파일 이름과 같은 경우에는 \0
스트림에서도 사용할 수 있습니다.
grep
친구들은 계속해서 기본 텍스트 필터 역할을 합니다. 그것은 먹는다철사표준 입력 또는 파일에서 주어진 정규 표현식과 일치하고 일치하는(또는 반대 -v
) 행 또는 섹션( -o
)을 다음과 같이 제공합니다.표준 출력, 아직 사용하기에 안전하지 않은 또 다른 스트림입니다.
이는 대부분의 코드 및 시와 같이 개행으로 구분된 텍스트에 작동하지만 파일 이름에는 작동하지 않습니다. 파일 이름에는 줄 바꿈이 포함될 수 있으며 grep
파일에는 두 개의 별도 줄이 표시될 수 있습니다 ls
.
Unix 셸의 프로그램에서 와일드카드는 어떻게 보입니까?
UNIX 쉘에서 와일드카드 문자는 대상 프로그램이 아닌 쉘에 의해 처리됩니다. 이는 혼란을 야기하고 해당 test*
섹션이 관련성이 있다고 생각하게 만드는 동시에 상황을 더욱 일관되게 만듭니다 ls
.
file 이 있다고 가정하면 test1
ls test2
는 test3
다음과 같습니다.
ls test1 test2 test3
그것은 기본적으로 당신이 그것에 무엇을 하는지 모릅니다.
내부적으로 test*
쉘로 확장성격. 이제 구조체가 있으므로 for varname in [word-list]; do [commands]; done
다음과 같이 할 수 있습니다.
for i in *; do
if i matches the pattern; then
do something
fi # that marks endif
done
[[
Bash에는 패턴 매칭을 수행할 수 있는 것이 있습니다 . 주어진 구조에 대해 [[ lhs == rhs ]]
bash는 그것이 lhs
위의 패턴과 일치하는지 확인합니다 rhs
. 우리의 경우에는 [[ $i == test* ]]
이 섹션을 사용할 수 있습니다 i matches the pattern
.최소 POSIX 셸에서는 사용할 수 없습니다 case
. 대신 사용하세요.
몇 가지 작업을 추가해야 합니다 do something
. Bash에는 배열이 있습니다:
# Arrays doesn't exist in POSIX standard too.
a=() # an empty array, since bash is weak-typed this doesn't mean anything
b=(foo bar baz) # array are assigned with, well, list-of-words.
for i in *; do
if [ $i == test* ]]; then
a+=("$i") # quoting avoids some word-splitting and you know what += is
fi # that marks endif
done
# and here do something to your lonely array, like those described in
# gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
여기에 한 가지 더. Unix 시스템에서는 관례적으로 .
숨겨진 파일은 로 시작하는 파일 이름으로 표시되며 *
포함되지 않습니다. .*
명시적으로 추가하되 .
현재 디렉터리를 나타내고 ..
basedir(Windows와 동일)을 나타내므로 제거하려고 합니다. .[!.]*
점, 점이 아닌 문자 및 0 문자를 포함한 모든 숫자를 의미하므로 사용이 가능합니다. 로 시작하지 않기 test*
때문에 귀하의 비즈니스와 관련이 없습니다 .test
.
extglob
여러 패턴 "또는"의 경우 (글쎄, 먼저 실행) 항목을 사용하거나 shopt -s extglob
여러 패턴을 허용하는 장소로 전체를 래핑할 수 있습니다 @(patt1|patt2)
.case
그런데 왜 그런 것이 필요합니까? a=(test*)
. 을 사용 test*
하면 일치하는 단어 목록이 제공됩니다. 여러 모드의 경우 를 사용하세요 a=(test* tset*)
.
하지만 글로벌 매치가 실패하면 어떻게 될까요?
glob이 일치하는 항목이 없으면 단어 목록에 glob 패턴 자체로 유지됩니다. 이것은 게으른 쉘 사용자에게는 괜찮아 보일 수 있지만 우리와 같은 진지한 스크립터에게는 그렇지 않습니다.
shopt
nullglob
다행히 bash에는 glob 모드를 복원하지 않는 프로그램이 있습니다 . shopt -s nullglob
활성화하려면 먼저 사용하세요 . 이것을 다른 POSIX 셸에서 이식할 수 있도록 하려면 for-and-case 필터링으로 돌아가겠습니다.
사람들은 이 솔루션을 어떻게 얻나요 ls
?
--
와일드카드로 지정하려는 항목이 다음이 아닌 경우 test*
다음을 추가 하면 일부 옵션 에 대해 *test*
다음과 같은 파일 이름이 인식될 수 있습니다 . 옵션 종료 표시-test123
ls
--
관례에 따르면.
# So what you need is globbing:
echo test*
# But those are not clear enough since echo only adds spaces between them. Use newlines:
printf '%s\n' test*
# But our screen doesn't have so many lines. Ah, yes, ls can make it into columns:
ls -- test*
# But it lists the contents of the directory test233/. Let's ask it not to:
ls -d -- test*
# Oh, good enough, let's add some color and some pretty type indicator:
ls -dF --color=auto -- test*
따라서 귀하의 간단한 질문은 다음과 같습니다 ls -d test*
. 하지만 그것은아니요단일 명령의 경우 ls
예쁜 인쇄에만 사용합니다.
그렇다면 파이프의 파일 이름은 항상 멍청합니까?
\0
아니요. 일부 프로그램은 구분 기호(예: find -print0
및 ) 를 추가/사용하여 xargs -0
사람들이 사용하기에 안전하다고 생각하도록 만듭니다 . 불행히도 그것은 필요합니다몇 가지 팁쉘이 이를 받아들이도록 하십시오 \0
. 그래서...
많은 쉘에는 여전히 더 나은 와일드카드 솔루션이 있습니다. find
디렉터리를 재귀적으로 탐색하고 조건에 따라 발견된 파일 이름을 인쇄합니다. 이는 종종 파일을 재귀적으로 나열하는 데 사용됩니다. Bash에는 다음이 있습니다.
shopt -s globstar
for i in **; do
try-some-test || continue
do-something
done
잘한 일이에요.
그러나 bash
모든 것을 제공하지는 않습니다. 예를 들어 깔끔한 병렬 명령이 없으며 결코 네이티브 코드만큼 빠르게 실행되지 않습니다. 그렇기 때문에 사람들은 다른 프로그램을 사용하여 parallel
작업을 수행합니다. 이제 우리는 그것을 가지고 있으므로 \0
그다지 나쁘지 않으며 find -print0
먹일 수 있습니다.
답변2
그러면 "test"로 시작하는 파일만 반환됩니다.
ls | grep '^test'
더 많은 예시:
그러면 "test"라는 단어가 포함된 행만 반환됩니다. 레코드당 1개의 행을 얻기 위해 "ls" 대신 ls -al"을 사용했습니다.
ls -al | grep "test"
그러면 test 또는 word2가 포함된 모든 행이 반환됩니다.
ls -al | grep "test\|word2"
그러면 "test" 문자열이 포함되지 않은 모든 행이 반환됩니다.
ls -al | grep -v "test"
실제로 열 단위로 수행하려면 다음을 수행할 수 있습니다.
ls -al | awk '$9 ~ /^test/'
여기서 $9는 내 데비안 컴퓨터의 파일 이름을 나타내는 열 9를 나타내고 아래 정규 표현식은 "test"로 시작한다는 의미입니다. awk는 필드 구분 기호로 처리되는 공백 및/또는 탭 및/또는 개행 문자로 열을 구분합니다.
답변3
beginning
"test"(또는 더 복잡한)가 포함된 모든 파일을 필터링하려면 egrep을 사용하여 정규식 패턴 일치를 적용할 수 있습니다 .
ls 출력에서 이 문자로 시작하는 파일을 검색하세요.D
$ ls |egrep "^D"
Desktop
Documents
Downloads
Dropbox
정규식을 사용하지 않으면 다음과 같은 결과가 나타납니다.
$ ls |grep D
Desktop
Documents
Downloads
Dropbox
README
Vuze Downloads