このxargsコマンドが機能しないのはなぜですか?


14

すべての.sh拡張子を削除したかったので、次のようにしました。

ls *.sh | xargs -I {} mv {} `basename {} .sh`

ただし、機能しませんが、basename変更されていないファイル名を返すように動作します。

なぜそのように振る舞うのですか?

たとえば、これは機能します:

ls *.sh | xargs -I {} echo `basename {}.jpg .jpg`;

編集

解決策:単一引用符は`basename ...`、コマンドが実行される前にシェルによる評価を防ぎます。

ls *.sh | xargs -I {}  sh -c 'mv {} `basename {} .sh`'

回答:


12

basenameコマンドはパイプラインが実行される前に実行されるためです。これを機能させるには、basenameを実行するxargsが必要ですsh -c。たとえば、次のようにします。

ls *.sh | xargs -L1 sh -c 'basename $1 .sh' dummy

ノート:

  • xargsファイル名を挿入する場所を指定しないと、コマンドラインの最後に追加されます。
  • -L1スイッチまたは同等のスイッチを使用する必要があるため、xargs1つの引数のみをに渡しますsh
  • の出力を使用すると、望ましくない効果ls生じる場合があります。

編集

廃止されたオプションを削除、TechZillaに感謝


3
最初の点は、-iオプションに対応するデフォルトである場合を除き、正しくありませんが、これらの「クラシック」オプションは廃止されています。たとえば、オプション/行を1つだけ使用する場合、新しいPOSIXのマニュアルページではを推奨してい-L1ます。の古い動作を呼び出すため-iに、ページは-I'{}'オプションを推奨しています。
JMベッカー

そのため、実際には ''ではなく ''記号です。私は推測します」のシェル評価を防ぎます。編集内容をご覧ください。
majkinetor

@TechZilla:修正してくれてありがとう。@majkinetor:はい、いいえ、評価を遅らせる必要がありますが、バックティック( `)を使用できるとは思いません。
トール

1
@majkinetor:ああ、私はあなたの今の意味がわかります。この方法でファイルの名前を変更するには、代わりにを使用しますrename(例:)rename 's/\.sh//' *.sh。最初に予行演習(-n)で試してください。
トール

1
@majkinetor:素晴らしくrename機能し、かなりシンプルですが、ディストリビューション固有のものであることを忘れないでください。RHELとDebianベースのディストリビューションは異なるrenameコマンドを提供するため、クロスディストリビューションスクリプトを作成する際には、そのことに留意する必要があります。
JMベッカー

4

あなたの質問については確信が持てませんが、実際に最初の行が機能しない理由を尋ねていますか?または、すべての.shファイルの名前を変更する適切な方法を探していますか?

それが最もクリーンな方法であると仮定すると、私は前にコマンドオプションを準備することを好みますxargs。.shファイル拡張子を削除するために、私はこのアプローチをよく考えます。

 find -maxdepth 1 -type f -iname '*.sh'  | sed 'p;s_.sh$__' | xargs -L2 mv
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.