題 Linux命令行/按字典順序過濾的文件


我在一個名為的目錄中有一些文件 IMG_0001.jpg ... IMG_9999.jpg。我想將按字典順序排列的文件移到另一個目錄中 IMG_9431.jpg 我怎樣才能做到這一點?


4
2017-09-16 08:47


起源




答案:


您可以使用 sort 和 sed 獲取比某些字符串更大的文件列表,如下所示:

$ ls -v
0?#Li  23?24  E.See  NULib  Yoush  ce-Su  edint  ethat  ibble  itwil  lines  of16   plesA  ryGen  t6?#C  witht  #ver
0?#mo  25?i   Examp  NYWAR  along  cribb  edist  ev     ibrar  ix B.  mapfo  ofthe  ppend  sdist  tetot  y8?#9  (atyo
0,22   27?#   FORAP  NextA  areFo  dacop  edwar  frees  ic11   lPubl  mored  oftwa  publi  sefor  theGN  yGene  )1995
1.scr  02111  Finla  Peter  aryis  datio  eful,  ftheG  ight(  landJ  mport  on23#  ralPu  se,or  tunde  yofth  ,USA.
1-200  ARTIC  GIMPT  RANTY  avere  difyi  eitan  ftwar  imbal  lbeus  ncerK  on,MA  raryG  shedb  t,wri  ytheF  ;ifno
2John  Appen  HANTA  Softw  bleof  dix B  enera  ght(C  impli  ld7?#  nc.,5  oolki  raryi  simpl  ublic  #19?#  ;with
4?#Th  BILIT  HOUTA  TNESS  blic2  e.py4  enthe  gtk26  ingar  lePla  ngpix  opyri  rdraw  sion.  ucanr  #Bost   Code
5?#GT  Backi  K-The  U17?#  brary  e.pyB  eralP  he21   ion)a  lesPr  nseas  oshMa  reeSo  sion2  undat  #Free
9Temp  Conte  Libra  ULARP  cDona  eExam  ermso  hehop  ion,I  lesTa  ntsB.  ouldh  re;yo  slibr  uropt  #Lice
13?#1  Copyr  Licen  URPOS  ceive  eFoun  erver  her12  islib  lescr  nylat  outev  ribut  s,Spe  utWIT  #MERC
15?#b  C)200  Matti  YorFI  cense  eGNUL  etail  hisli  ite33  lesim  n;eit  ple.p  rthet  s.18   vpyth  #Thi

$ mkdir greater-than-sion

這是魔術:

$ find -type f -print0 | 
  sort -z |
  sed -z '1,/sion/d' | 
  xargs -0 mv -t greater-than-sion

行:

  1. 打印文件列表,以。分隔 NUL 而不是換行符(-print0
  2. 排序他們
  3. 刪除行 低於 (包括)一些字符串(這裡 sion) - 請注意,這僅適用於GNU sed,實現了 -z 解析選項 NUL - 終止輸入
  4. 將此列表傳遞給 mv 同 xargs

並且期望的結果:

$ ls -R
.:
 Code  ;ifno  25?i   avere  Conte  edist  erver  GIMPT               ic11   K-The  lines  nseas  opyri  raryG  se,or
#19?#  ;with  27?#   Backi  Copyr  edwar  etail  greater-than-sion/  ight(  landJ  lPubl  ntsB.  oshMa  raryi  sefor
#Bost  0?#Li  2John  BILIT  cribb  eExam  ethat  gtk26               imbal  lbeus  mapfo  NULib  ouldh  rdraw  shedb
#Free  0?#mo  4?#Th  bleof  dacop  eFoun  ev     HANTA               impli  ld7?#  Matti  nylat  outev  re;yo  simpl
#Lice  0,22   5?#GT  blic2  datio  eful,  Examp  he21                ingar  lePla  mored  NYWAR  Peter  reeSo  sion.
#MERC  02111  9Temp  brary  difyi  eGNUL  Finla  hehop               ion)a  lescr  mport  of16   ple.p  ribut
#Thi   1.scr  along  C)200  dix B  eitan  FORAP  her12               ion,I  lesim  n;eit  ofthe  plesA  rthet
#ver   1-200  Appen  cDona  e.py4  enera  frees  hisli               islib  lesPr  nc.,5  oftwa  ppend  ryGen
(atyo  13?#1  areFo  ceive  e.pyB  enthe  ftheG  HOUTA               ite33  lesTa  ncerK  on,MA  publi  s,Spe
)1995  15?#b  ARTIC  cense  E.See  eralP  ftwar  ibble               itwil  Libra  NextA  on23#  ralPu  s.18
,USA.  23?24  aryis  ce-Su  edint  ermso  ght(C  ibrar               ix B.  Licen  ngpix  oolki  RANTY  sdist

./greater-than-sion:
sion2  Softw  t6?#C  theGN  tunde  ublic  ULARP  uropt  utWIT  witht  yGene  YorFI  ytheF
slibr  t,wri  tetot  TNESS  U17?#  ucanr  undat  URPOS  vpyth  y8?#9  yofth  Yoush

4
2017-09-16 10:52



好一個。我完全忘記了 sed 這裡。 - slhck
'sed -z'有什麼作用?做了快速檢查,找不到選項-z的解釋。 - jaychris
處理由空字符而不是換行符分隔的行。 這在手冊中說明。 - Ярослав Рахматуллин
注意,這是一個僅GNU選項,因此不是BSD sed。 (cc @jaychris) - slhck
謝謝Ярослав&slhck。我嘗試了手冊和谷歌搜索,但沒有得到這個選項。好像我訪問的sed不是GNU版本。 - jaychris


支撐擴張,在Bash 3及以上版本中可用,以及Zsh和其他幾種外殼:*

mv IMG_{9431..9999}.jpg some_other_dir

大括號將擴展到9431和9999之間的所有數字,因此它相當於寫出:

mv IMG_9431.jpg IMG_9432.jpg … IMG_9999.jpg some_other_dir

如果文件太多,這將失敗(請參閱 這篇文章關於 ARG_MAX 背景信息。)

如果你的shell缺少大括號擴展功能,或者你有太多的文件,你可以這樣做 - 這可能會慢一點:

for n in $(seq 9431 9999); do mv "IMG_$n.jpg" some_other_dir; done

如果你真的想按字典順序排序,請看一下 ЯрославРахматуллин的答案。比這裡的內容好多了。

你必須以某種方式對文件名進行排序。這就是我快速實現的目標,它並不漂亮,遠非理想。它適用於GNU / Linux(grepsortxargs並處理任何文件名,包括引號和空格。

tmp="$(mktemp /tmp/files.XXX)"
find . -type f -name 'IMG*'  -maxdepth 1 -print0 | sort -z > "$tmp"
line=$(grep -nz IMG_9984.jpg "$tmp" | cut -d: -f1)
tr '\0\n' '\n\0' < "$tmp" | tail -n "+$line" | tr '\0\n' '\n\0' |
xargs -0 -I{} echo mv {} some_other_dir
rm "$tmp"

除掉 echo 當你確定這可以做你想要的。我們在這裡做什麼:

  • 創建一個臨時文件來保存文件名。

  • 查找與模式匹配的所有文件,並將它們排序為臨時文件。記錄由分隔 NUL 人物(-print0-z)所以我們可以處理任何文件名。

  • 找到文件名的“行”號,例如 IMG_9984.jpg

  • 交換 NUL 和臨時文件中的換行符 所以 tail 可以處理它

  • 把它們交換回來 xargs 可以處理它(-0)和 mv 文件到另一個目錄。

如果我們不必處理包含引號或空格的文件,這會更容易,但......這就是我。最好是安全而不是抱歉。


6
2017-09-16 09:03



或許注意它是Bash特定的(?)。更奇特的一點是,如果一個擴展到總數超過ARG_MAX參數,它將失敗。但是,在這種情況下需要幾個數量級。 - Daniel Andersson
@DanielAndersson我打算為舊版/替代版添加一個解決方案。它在Bash 3及以上版本中,也在Zsh和ksh中,可能還有其他版本。 - slhck
只是為了知識,如果文件中沒有模式我怎麼會這樣做,我只想讓所有文件“按字典順序大於”特定的文件名? - Paralife
@Paralife可能很棘手 - 請參閱我的最新答案。但Ярослав的解決方案肯定更直截了當。 - slhck
好的,這裡有什麼?給Ярослав更通用的解決方案提供已接受的答案,這也可能對其他情況有用,或留下這個接受的答案,因為它解決了我問的具體問題並且更簡單? - Paralife