![](/img/trans.png)
[英]How to list all the files matching criteria and select first file using shell script?
[英]Shell Script - list files, read files and write data to new file
我對shell腳本有一個特殊的問題。
簡單的腳本對我來說不是問題,但我是新手,想讓我成為一個簡單的數據庫文件。
所以,我想做的是:
- Search for filetypes (i.e. .nfo) <-- should be no problem :)
- read inside of each found file and use some strings inside
- these string of each file should be written in a new file. Each found file informations
應該是新文件中的一行
我希望我解釋我的“項目”很好。
我現在的問題是,要了解我如何告訴腳本它必須搜索文件,然后使用這些文件中的每個文件讀入並使用其中的一些信息將其寫入新文件。
我會更好地解釋一下。
我正在搜索文件,這讓我回頭:
file1.nfo
file2.nfo
file3.nfo
好了,現在在每個文件中我需要2行之間的信息。 即
file1.nfo:
<user>test1</user>
file2.nfo:
<user>test2</user>
所以在新文件中現在應該是:
file1.nfo:user1
file2.nfo:user2
好的:
find -name *.nfo > /test/database.txt
正在打印出文件列表。 和
sed -n '/<user*/,/<\/user>/p' file1.nfo
給了我完整的文件,而不僅僅是<user>
和</user>
之間的信息
我試着一步一步地繼續閱讀,但是看起來非常困難。
我做錯了什么,應該是列出所有文件的最佳方法,並將文件和兩個字符串之間的內容寫入文件?
編輯新:
好的,這是更多信息的更新。 我現在學到了很多,並在網上搜索我的問題。 我可以找到很多信息,但我不知道如何將它們放在一起,以便我可以使用它。
現在用awk工作就是我得到了文件名和字符串。
這里現在完整的信息(我想我可以繼續自己有點幫助,但我不能:()
下面是一個示例:/test/file1.nfo
<string1>STRING 1</string1>
<string2>STRING 2</string2>
<string3>STRING 3</string3>
<string4>STRING 4</string4>
<personal informations>
<hobby>Baseball</hobby>
<hobby>Baskeball</hobby>
</personal informations>
這是/test/file2.nof的一個例子
<string1>STRING 1</string1>
<string2>STRING 2</string2>
<string3>STRING 3</string3>
<string4>STRING 4</string4>
<personal informations>
<hobby>Soccer</hobby>
<hobby>Traveling</hobby>
</personal informations>
我想要創建的文件必須如下所示。
STRING 1:::/test/file1.nfo:::Date of file:::STRING 4:::STRING 3:::Baseball, Basketball:::STRING 2
STRING 1:::/test/file2.nfo:::Date of file:::STRING 4:::STRING 3:::Baseball, Basketball:::STRING 2
“文件日期”應該是文件的創建日期。 所以我可以看到文件的年齡。
所以,這就是我需要的東西,看起來並不容易。
非常感謝。
UPATE ERROR -printf
find: unrecognized: -printf
Usage: find [PATH]... [OPTIONS] [ACTIONS]
Search for files and perform actions on them.
First failed action stops processing of current file.
Defaults: PATH is current directory, action is '-print'
-follow Follow symlinks
-xdev Don't descend directories on other filesystems
-maxdepth N Descend at most N levels. -maxdepth 0 applies
actions to command line arguments only
-mindepth N Don't act on first N levels
-depth Act on directory *after* traversing it
Actions:
( ACTIONS ) Group actions for -o / -a
! ACT Invert ACT's success/failure
ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2
ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2
Note: -a has higher priority than -o
-name PATTERN Match file name (w/o directory name) to PATTERN
-iname PATTERN Case insensitive -name
-path PATTERN Match path to PATTERN
-ipath PATTERN Case insensitive -path
-regex PATTERN Match path to regex PATTERN
-type X File type is X (one of: f,d,l,b,c,...)
-perm MASK At least one mask bit (+MASK), all bits (-MASK),
or exactly MASK bits are set in file's mode
-mtime DAYS mtime is greater than (+N), less than (-N),
or exactly N days in the past
-mmin MINS mtime is greater than (+N), less than (-N),
or exactly N minutes in the past
-newer FILE mtime is more recent than FILE's
-inum N File has inode number N
-user NAME/ID File is owned by given user
-group NAME/ID File is owned by given group
-size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))
+/-N: file size is bigger/smaller than N
-links N Number of links is greater than (+N), less than (-N),
or exactly N
-prune If current file is directory, don't descend into it
If none of the following actions is specified, -print is assumed
-print Print file name
-print0 Print file name, NUL terminated
-exec CMD ARG ; Run CMD with all instances of {} replaced by
file name. Fails if CMD exits with nonzero
-delete Delete current file/directory. Turns on -depth option
sed的pat1,pat2
表示法是基於行的。 可以這樣想, pat1
為其命令設置啟用標志, pat2
禁用該標志。 如果pat1
和pat2
都在同一行,那么將設置標志,因此在您的情況下打印所有內容,包括<user>
行。 請參閱grymoire的sed howto了解更多信息。
在這種情況下,sed的替代方法是使用支持環視斷言的grep,例如GNU grep:
find . -type f -name '*.nfo' | xargs grep -oP '(?<=<user>).*(?=</user>)'
如果grep不支持-P
,你可以使用grep和sed的組合:
find . -type f -name '*.nfo' | xargs grep -o '<user>.*</user>' | sed 's:</\?user>::g'
輸出:
./file1.nfo:test1
./file2.nfo:test2
注意,您應該知道將文件傳遞給xargs
所涉及的問題,並且可能使用-exec ...
而不是。
碰巧grep以你需要的格式輸出,並且足以用於單行。
默認情況下, grep '' *.nfo
將輸出如下內容:
file1.nfo:random data
file1.nfo:<user>test1</user>
file1.nfo:some more random data
file2.nfo:not needed
file2.nfo:<user>test2</user>
file2.nfo:etc etc
通過添加-P
選項(Perl RegEx),您可以將輸出限制為僅匹配:
grep -P "<user>\w+<\/user>" *.nfo
輸出:
file1.nfo:<user>test1</user>
file2.nfo:<user>test2</user>
現在-o
選項(僅顯示匹配的內容)可以保存當天,但由於不需要標記,我們需要更高級的RegEx:
grep -oP "(?<=<user>)\w+(?=<\/user>)" *.nfo > /test/database.txt
cat /test/database.txt
輸出:
file1.nfo:test1
file2.nfo:test2
在此解釋RegEx: http : //regex101.com/r/oU2wQ1
而你的整個腳本只是一個命令。
更新:
如果您沒有--perl-regexp
選項,請嘗試:
grep -oE "<user>\w+<\/user>" *.nfo|sed 's#</?user>##g' > /test/database.txt
所有你需要的是:
find -name '*.nfo' | xargs awk -F'[><]' '{print FILENAME,$3}'
如果您的文件中包含的內容多於您在示例輸入中顯示的內容,那么這可能就是您所需要的:
... awk -F'[><]' '/<user>/{print FILENAME,$3}' file
試試這個(未經測試):
> outfile
find -name '*.nfo' -printf "%p %Tc\n" |
while IFS= read -r fname tstamp
do
awk -v tstamp="$tstamp" -F'[><]' -v OFS=":::" '
{ a[$2] = a[$2] sep[$2] $3; sep[$2] = ", " }
END {
print a["string1"], FILENAME, tstamp, a["string4"], a["string3"], a["hobby"], a["string2"]
}
' "$fname" >> outfile
done
只有當您的文件名不包含空格時,上述操作才有效。 如果他們可以,我們需要調整循環。
如果你的發現不支持-printf(建議 - 認真考慮獲得一個現代的“發現”!):
> outfile
find -name '*.nfo' -print |
while IFS= read -r fname
do
tstamp=$(stat -c"%x" "$fname")
awk -v tstamp="$tstamp" -F'[><]' -v OFS=":::" '
{ a[$2] = a[$2] sep[$2] $3; sep[$2] = ", " }
END {
print a["string1"], FILENAME, tstamp, a["string4"], a["string3"], a["hobby"], a["string2"]
}
' "$fname" >> outfile
done
如果你沒有“stat”,那么google可以選擇從文件中獲取時間戳,或者考慮解析ls -l
的輸出 - 它是不可靠的,但如果它是你所有的......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.