コマンドラインから小さなユーティリティを作成しようとしています。現在の作業ディレクトリに最近追加されたファイルを見つけ、引数として指定された名前をmv
指定したいと思います。
私はこれでこれを達成しようとしてきました。
ls -tr | tail -n 1 | xargs -0 -J % mv % SQL_warning_2.png
...しかしbashは次のように報告します。
mv: rename Screenshot 2020-06-22 at 17.53.23.png
to SQL_warning_2.png: No such file or directory
私はこれがxargsがfilename:の空白を別の引数として渡すことを意味すると思いますが、私が知っている限りこれにフラグはありませScreenshot 2020-06-22 at 17.53.23.png
ん-print0
。ls
私の仮定の一部が間違っている場合は許してください。私はxargsについて非常に慣れていません。
答え1
ファイル名に改行文字が含まれていないと仮定しているようです(次をtail
使用して1つを選択します)。
ls -tr | tail -n 1 | xargs -I % mv -- % SQL_warning_2.png
これによりユーティリティが一度呼び出され-I %
ます。xargs
各ライン%
その行のテキストを読み、置き換えます。代わりに-J %
スペースで行を分けてください。
$ echo 1 2 3 | xargs -J {} printf '"%s"\n' {}
"1"
"2"
"3"
$ echo 1 2 3 | xargs -I {} printf '"%s"\n' {}
"1 2 3"
現在のディレクトリで最後に変更されたファイルの名前を変更したいようです。シェルを使用すると、zsh
次のことができます。
mv -- *(.om[1]) SQL_warning_2.png
mv
最後に変更された一般ファイル名を最初の引数として使用します。om[1]
mtime タイムスタンプに基づいて名前リストを並べ替え、最初の項目を選択する glob 修飾子です。前の点は通常のファイルのみを選択します(ディレクトリなどは選択しません)。
からbash
:
zsh -c 'mv -- *(.om[1]) SQL_warning_2.png'
答え2
私は次のようにします:
mv -- "$(ls -t|head -n1)" new_filename
(現在のディレクトリの最新のファイル名に改行文字が含まれていないとします。)
答え3
はい、使用するには-0
標準xargs
入力にNULで区切られたリストが必要です。ここでは、最後の改行の後に最新のファイルの名前部分を入力し、その後に改行を入力します(改行はファイル名ls
の一部ではなくファイル名として追加されます)。
その入力には NUL がないため、xargs
入力全体はmv
改行文字を含む 1 つの引数として渡されます。したがって、最新のファイル名に改行文字が1つだけ含まれていて、ファイル名の最後の文字である場合にのみ機能します。 。
ここでは、改行で区切られたリストではなくNULで区切られたリストを出力することを確認する必要がありますが、これを行う実装はありませんls
。ls
xargs
または、デフォルトの入力形式(除く-0
)に戻す必要があります。ここでは、引数はxargs
スペース(リストは実装と可能なロケールによって異なります)または改行で区切られ、およびと"..."
は'...'
これら\
の文字と互いをエスケープするために使用されます。同じシェル演算子を別の方法で引用できます。一部のxargs
実装では入力をテキストとして解釈しようとしますが、ファイル名にはすべてのバイト値(NULを除く)を含めることができるため、/
Cロケールでもこれを行う必要があります。
export LC_ALL=C
ls -td ./* | awk -v q="'" '
{gsub(/"/, "\"\\\"\"")} # escape "
NR == 1 {printf "\"%s", $0; next}
/\// {exit} # a / means the start of the second file
{printf "\"\\\n\"%s", $0} # escape newlines
END {if (NR) print "\""}' |
xargs -J % mv % newname
ご覧のとおり、xargs
安定して使用することはお尻に痛みがあります。いくつかのxargs
実装では、パラメータまたは入力ラインのサイズに対する制限は非常に低いです。これは-J
移植不可能なBSD拡張であることに注意してください。
ラインベースのユーティリティを使用して任意のファイル名を処理することもls
非常に困難です。
zsh
@Kusalanandaが提案したように、それを使用して変更時間ごとにファイルリストを並べ替えることをお勧めします。
mv -- *(.om[1]) newname
では、bash
次のこともできます。
IFS= read -rd / newest < <(ls -td ./*) && newest=${newest%.}
newest=${newest%?} # strip newline
[ -n "$newest" ] && mv "$newest" newname
(ksh93またはzshでも動作します)。前の方法と同様に、リスト内の2番目のファイルが始まる行を決定する機能をxargs
使用します。./*